162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci// ALSA SoC Audio Layer - Rockchip I2S/TDM Controller driver 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci// Copyright (c) 2018 Rockchip Electronics Co. Ltd. 562306a36Sopenharmony_ci// Author: Sugar Zhang <sugar.zhang@rock-chips.com> 662306a36Sopenharmony_ci// Author: Nicolas Frattaroli <frattaroli.nicolas@gmail.com> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/clk-provider.h> 1062306a36Sopenharmony_ci#include <linux/delay.h> 1162306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of_address.h> 1462306a36Sopenharmony_ci#include <linux/of_device.h> 1562306a36Sopenharmony_ci#include <linux/of_gpio.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci#include <linux/regmap.h> 1862306a36Sopenharmony_ci#include <linux/reset.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <sound/dmaengine_pcm.h> 2162306a36Sopenharmony_ci#include <sound/pcm_params.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "rockchip_i2s_tdm.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define DRV_NAME "rockchip-i2s-tdm" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DEFAULT_MCLK_FS 256 2862306a36Sopenharmony_ci#define CH_GRP_MAX 4 /* The max channel 8 / 2 */ 2962306a36Sopenharmony_ci#define MULTIPLEX_CH_MAX 10 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci#define TRCM_TXRX 0 3262306a36Sopenharmony_ci#define TRCM_TX 1 3362306a36Sopenharmony_ci#define TRCM_RX 2 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistruct txrx_config { 3662306a36Sopenharmony_ci u32 addr; 3762306a36Sopenharmony_ci u32 reg; 3862306a36Sopenharmony_ci u32 txonly; 3962306a36Sopenharmony_ci u32 rxonly; 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistruct rk_i2s_soc_data { 4362306a36Sopenharmony_ci u32 softrst_offset; 4462306a36Sopenharmony_ci u32 grf_reg_offset; 4562306a36Sopenharmony_ci u32 grf_shift; 4662306a36Sopenharmony_ci int config_count; 4762306a36Sopenharmony_ci const struct txrx_config *configs; 4862306a36Sopenharmony_ci int (*init)(struct device *dev, u32 addr); 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct rk_i2s_tdm_dev { 5262306a36Sopenharmony_ci struct device *dev; 5362306a36Sopenharmony_ci struct clk *hclk; 5462306a36Sopenharmony_ci struct clk *mclk_tx; 5562306a36Sopenharmony_ci struct clk *mclk_rx; 5662306a36Sopenharmony_ci struct regmap *regmap; 5762306a36Sopenharmony_ci struct regmap *grf; 5862306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture_dma_data; 5962306a36Sopenharmony_ci struct snd_dmaengine_dai_dma_data playback_dma_data; 6062306a36Sopenharmony_ci struct reset_control *tx_reset; 6162306a36Sopenharmony_ci struct reset_control *rx_reset; 6262306a36Sopenharmony_ci struct rk_i2s_soc_data *soc_data; 6362306a36Sopenharmony_ci bool is_master_mode; 6462306a36Sopenharmony_ci bool io_multiplex; 6562306a36Sopenharmony_ci bool tdm_mode; 6662306a36Sopenharmony_ci unsigned int frame_width; 6762306a36Sopenharmony_ci unsigned int clk_trcm; 6862306a36Sopenharmony_ci unsigned int i2s_sdis[CH_GRP_MAX]; 6962306a36Sopenharmony_ci unsigned int i2s_sdos[CH_GRP_MAX]; 7062306a36Sopenharmony_ci int refcount; 7162306a36Sopenharmony_ci spinlock_t lock; /* xfer lock */ 7262306a36Sopenharmony_ci bool has_playback; 7362306a36Sopenharmony_ci bool has_capture; 7462306a36Sopenharmony_ci struct snd_soc_dai_driver *dai; 7562306a36Sopenharmony_ci}; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_cistatic int to_ch_num(unsigned int val) 7862306a36Sopenharmony_ci{ 7962306a36Sopenharmony_ci switch (val) { 8062306a36Sopenharmony_ci case I2S_CHN_4: 8162306a36Sopenharmony_ci return 4; 8262306a36Sopenharmony_ci case I2S_CHN_6: 8362306a36Sopenharmony_ci return 6; 8462306a36Sopenharmony_ci case I2S_CHN_8: 8562306a36Sopenharmony_ci return 8; 8662306a36Sopenharmony_ci default: 8762306a36Sopenharmony_ci return 2; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic void i2s_tdm_disable_unprepare_mclk(struct rk_i2s_tdm_dev *i2s_tdm) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci clk_disable_unprepare(i2s_tdm->mclk_tx); 9462306a36Sopenharmony_ci clk_disable_unprepare(i2s_tdm->mclk_rx); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/** 9862306a36Sopenharmony_ci * i2s_tdm_prepare_enable_mclk - prepare to enable all mclks, disable them on 9962306a36Sopenharmony_ci * failure. 10062306a36Sopenharmony_ci * @i2s_tdm: rk_i2s_tdm_dev struct 10162306a36Sopenharmony_ci * 10262306a36Sopenharmony_ci * This function attempts to enable all mclk clocks, but cleans up after 10362306a36Sopenharmony_ci * itself on failure. Guarantees to balance its calls. 10462306a36Sopenharmony_ci * 10562306a36Sopenharmony_ci * Returns success (0) or negative errno. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic int i2s_tdm_prepare_enable_mclk(struct rk_i2s_tdm_dev *i2s_tdm) 10862306a36Sopenharmony_ci{ 10962306a36Sopenharmony_ci int ret = 0; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ret = clk_prepare_enable(i2s_tdm->mclk_tx); 11262306a36Sopenharmony_ci if (ret) 11362306a36Sopenharmony_ci goto err_mclk_tx; 11462306a36Sopenharmony_ci ret = clk_prepare_enable(i2s_tdm->mclk_rx); 11562306a36Sopenharmony_ci if (ret) 11662306a36Sopenharmony_ci goto err_mclk_rx; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cierr_mclk_rx: 12162306a36Sopenharmony_ci clk_disable_unprepare(i2s_tdm->mclk_tx); 12262306a36Sopenharmony_cierr_mclk_tx: 12362306a36Sopenharmony_ci return ret; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_cistatic int __maybe_unused i2s_tdm_runtime_suspend(struct device *dev) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci regcache_cache_only(i2s_tdm->regmap, true); 13162306a36Sopenharmony_ci i2s_tdm_disable_unprepare_mclk(i2s_tdm); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci clk_disable_unprepare(i2s_tdm->hclk); 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic int __maybe_unused i2s_tdm_runtime_resume(struct device *dev) 13962306a36Sopenharmony_ci{ 14062306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); 14162306a36Sopenharmony_ci int ret; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci ret = clk_prepare_enable(i2s_tdm->hclk); 14462306a36Sopenharmony_ci if (ret) 14562306a36Sopenharmony_ci goto err_hclk; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ret = i2s_tdm_prepare_enable_mclk(i2s_tdm); 14862306a36Sopenharmony_ci if (ret) 14962306a36Sopenharmony_ci goto err_mclk; 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci regcache_cache_only(i2s_tdm->regmap, false); 15262306a36Sopenharmony_ci regcache_mark_dirty(i2s_tdm->regmap); 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci ret = regcache_sync(i2s_tdm->regmap); 15562306a36Sopenharmony_ci if (ret) 15662306a36Sopenharmony_ci goto err_regcache; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci return 0; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cierr_regcache: 16162306a36Sopenharmony_ci i2s_tdm_disable_unprepare_mclk(i2s_tdm); 16262306a36Sopenharmony_cierr_mclk: 16362306a36Sopenharmony_ci clk_disable_unprepare(i2s_tdm->hclk); 16462306a36Sopenharmony_cierr_hclk: 16562306a36Sopenharmony_ci return ret; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic inline struct rk_i2s_tdm_dev *to_info(struct snd_soc_dai *dai) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci return snd_soc_dai_get_drvdata(dai); 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci/* 17462306a36Sopenharmony_ci * Makes sure that both tx and rx are reset at the same time to sync lrck 17562306a36Sopenharmony_ci * when clk_trcm > 0. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_cistatic void rockchip_snd_xfer_sync_reset(struct rk_i2s_tdm_dev *i2s_tdm) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci /* This is technically race-y. 18062306a36Sopenharmony_ci * 18162306a36Sopenharmony_ci * In an ideal world, we could atomically assert both resets at the 18262306a36Sopenharmony_ci * same time, through an atomic bulk reset API. This API however does 18362306a36Sopenharmony_ci * not exist, so what the downstream vendor code used to do was 18462306a36Sopenharmony_ci * implement half a reset controller here and require the CRU to be 18562306a36Sopenharmony_ci * passed to the driver as a device tree node. Violating abstractions 18662306a36Sopenharmony_ci * like that is bad, especially when it influences something like the 18762306a36Sopenharmony_ci * bindings which are supposed to describe the hardware, not whatever 18862306a36Sopenharmony_ci * workarounds the driver needs, so it was dropped. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * In practice, asserting the resets one by one appears to work just 19162306a36Sopenharmony_ci * fine for playback. During duplex (playback + capture) operation, 19262306a36Sopenharmony_ci * this might become an issue, but that should be solved by the 19362306a36Sopenharmony_ci * implementation of the aforementioned API, not by shoving a reset 19462306a36Sopenharmony_ci * controller into an audio driver. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci reset_control_assert(i2s_tdm->tx_reset); 19862306a36Sopenharmony_ci reset_control_assert(i2s_tdm->rx_reset); 19962306a36Sopenharmony_ci udelay(10); 20062306a36Sopenharmony_ci reset_control_deassert(i2s_tdm->tx_reset); 20162306a36Sopenharmony_ci reset_control_deassert(i2s_tdm->rx_reset); 20262306a36Sopenharmony_ci udelay(10); 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_cistatic void rockchip_snd_reset(struct reset_control *rc) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci reset_control_assert(rc); 20862306a36Sopenharmony_ci udelay(10); 20962306a36Sopenharmony_ci reset_control_deassert(rc); 21062306a36Sopenharmony_ci udelay(10); 21162306a36Sopenharmony_ci} 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_cistatic void rockchip_snd_xfer_clear(struct rk_i2s_tdm_dev *i2s_tdm, 21462306a36Sopenharmony_ci unsigned int clr) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci unsigned int xfer_mask = 0; 21762306a36Sopenharmony_ci unsigned int xfer_val = 0; 21862306a36Sopenharmony_ci unsigned int val; 21962306a36Sopenharmony_ci int retry = 10; 22062306a36Sopenharmony_ci bool tx = clr & I2S_CLR_TXC; 22162306a36Sopenharmony_ci bool rx = clr & I2S_CLR_RXC; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (!(rx || tx)) 22462306a36Sopenharmony_ci return; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (tx) { 22762306a36Sopenharmony_ci xfer_mask = I2S_XFER_TXS_START; 22862306a36Sopenharmony_ci xfer_val = I2S_XFER_TXS_STOP; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci if (rx) { 23162306a36Sopenharmony_ci xfer_mask |= I2S_XFER_RXS_START; 23262306a36Sopenharmony_ci xfer_val |= I2S_XFER_RXS_STOP; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_XFER, xfer_mask, xfer_val); 23662306a36Sopenharmony_ci udelay(150); 23762306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci regmap_read(i2s_tdm->regmap, I2S_CLR, &val); 24062306a36Sopenharmony_ci /* Wait on the clear operation to finish */ 24162306a36Sopenharmony_ci while (val) { 24262306a36Sopenharmony_ci udelay(15); 24362306a36Sopenharmony_ci regmap_read(i2s_tdm->regmap, I2S_CLR, &val); 24462306a36Sopenharmony_ci retry--; 24562306a36Sopenharmony_ci if (!retry) { 24662306a36Sopenharmony_ci dev_warn(i2s_tdm->dev, "clear failed, reset %s%s\n", 24762306a36Sopenharmony_ci tx ? "tx" : "", rx ? "rx" : ""); 24862306a36Sopenharmony_ci if (rx && tx) 24962306a36Sopenharmony_ci rockchip_snd_xfer_sync_reset(i2s_tdm); 25062306a36Sopenharmony_ci else if (tx) 25162306a36Sopenharmony_ci rockchip_snd_reset(i2s_tdm->tx_reset); 25262306a36Sopenharmony_ci else if (rx) 25362306a36Sopenharmony_ci rockchip_snd_reset(i2s_tdm->rx_reset); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic inline void rockchip_enable_tde(struct regmap *regmap) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE, 26262306a36Sopenharmony_ci I2S_DMACR_TDE_ENABLE); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void rockchip_disable_tde(struct regmap *regmap) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE, 26862306a36Sopenharmony_ci I2S_DMACR_TDE_DISABLE); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic inline void rockchip_enable_rde(struct regmap *regmap) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE, 27462306a36Sopenharmony_ci I2S_DMACR_RDE_ENABLE); 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic inline void rockchip_disable_rde(struct regmap *regmap) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE, 28062306a36Sopenharmony_ci I2S_DMACR_RDE_DISABLE); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* only used when clk_trcm > 0 */ 28462306a36Sopenharmony_cistatic void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream, 28562306a36Sopenharmony_ci struct snd_soc_dai *dai, int on) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); 28862306a36Sopenharmony_ci unsigned long flags; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci spin_lock_irqsave(&i2s_tdm->lock, flags); 29162306a36Sopenharmony_ci if (on) { 29262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 29362306a36Sopenharmony_ci rockchip_enable_tde(i2s_tdm->regmap); 29462306a36Sopenharmony_ci else 29562306a36Sopenharmony_ci rockchip_enable_rde(i2s_tdm->regmap); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci if (++i2s_tdm->refcount == 1) { 29862306a36Sopenharmony_ci rockchip_snd_xfer_sync_reset(i2s_tdm); 29962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_XFER, 30062306a36Sopenharmony_ci I2S_XFER_TXS_START | 30162306a36Sopenharmony_ci I2S_XFER_RXS_START, 30262306a36Sopenharmony_ci I2S_XFER_TXS_START | 30362306a36Sopenharmony_ci I2S_XFER_RXS_START); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci } else { 30662306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 30762306a36Sopenharmony_ci rockchip_disable_tde(i2s_tdm->regmap); 30862306a36Sopenharmony_ci else 30962306a36Sopenharmony_ci rockchip_disable_rde(i2s_tdm->regmap); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci if (--i2s_tdm->refcount == 0) { 31262306a36Sopenharmony_ci rockchip_snd_xfer_clear(i2s_tdm, 31362306a36Sopenharmony_ci I2S_CLR_TXC | I2S_CLR_RXC); 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci spin_unlock_irqrestore(&i2s_tdm->lock, flags); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void rockchip_snd_txctrl(struct rk_i2s_tdm_dev *i2s_tdm, int on) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci if (on) { 32262306a36Sopenharmony_ci rockchip_enable_tde(i2s_tdm->regmap); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_XFER, 32562306a36Sopenharmony_ci I2S_XFER_TXS_START, 32662306a36Sopenharmony_ci I2S_XFER_TXS_START); 32762306a36Sopenharmony_ci } else { 32862306a36Sopenharmony_ci rockchip_disable_tde(i2s_tdm->regmap); 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci rockchip_snd_xfer_clear(i2s_tdm, I2S_CLR_TXC); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic void rockchip_snd_rxctrl(struct rk_i2s_tdm_dev *i2s_tdm, int on) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci if (on) { 33762306a36Sopenharmony_ci rockchip_enable_rde(i2s_tdm->regmap); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_XFER, 34062306a36Sopenharmony_ci I2S_XFER_RXS_START, 34162306a36Sopenharmony_ci I2S_XFER_RXS_START); 34262306a36Sopenharmony_ci } else { 34362306a36Sopenharmony_ci rockchip_disable_rde(i2s_tdm->regmap); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci rockchip_snd_xfer_clear(i2s_tdm, I2S_CLR_RXC); 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai, 35062306a36Sopenharmony_ci unsigned int fmt) 35162306a36Sopenharmony_ci{ 35262306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai); 35362306a36Sopenharmony_ci unsigned int mask, val, tdm_val, txcr_val, rxcr_val; 35462306a36Sopenharmony_ci int ret; 35562306a36Sopenharmony_ci bool is_tdm = i2s_tdm->tdm_mode; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(cpu_dai->dev); 35862306a36Sopenharmony_ci if (ret < 0 && ret != -EACCES) 35962306a36Sopenharmony_ci return ret; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci mask = I2S_CKR_MSS_MASK; 36262306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { 36362306a36Sopenharmony_ci case SND_SOC_DAIFMT_BP_FP: 36462306a36Sopenharmony_ci val = I2S_CKR_MSS_MASTER; 36562306a36Sopenharmony_ci i2s_tdm->is_master_mode = true; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci case SND_SOC_DAIFMT_BC_FC: 36862306a36Sopenharmony_ci val = I2S_CKR_MSS_SLAVE; 36962306a36Sopenharmony_ci i2s_tdm->is_master_mode = false; 37062306a36Sopenharmony_ci break; 37162306a36Sopenharmony_ci default: 37262306a36Sopenharmony_ci ret = -EINVAL; 37362306a36Sopenharmony_ci goto err_pm_put; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CKR, mask, val); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci mask = I2S_CKR_CKP_MASK | I2S_CKR_TLP_MASK | I2S_CKR_RLP_MASK; 37962306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_INV_MASK) { 38062306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_NF: 38162306a36Sopenharmony_ci val = I2S_CKR_CKP_NORMAL | 38262306a36Sopenharmony_ci I2S_CKR_TLP_NORMAL | 38362306a36Sopenharmony_ci I2S_CKR_RLP_NORMAL; 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case SND_SOC_DAIFMT_NB_IF: 38662306a36Sopenharmony_ci val = I2S_CKR_CKP_NORMAL | 38762306a36Sopenharmony_ci I2S_CKR_TLP_INVERTED | 38862306a36Sopenharmony_ci I2S_CKR_RLP_INVERTED; 38962306a36Sopenharmony_ci break; 39062306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_NF: 39162306a36Sopenharmony_ci val = I2S_CKR_CKP_INVERTED | 39262306a36Sopenharmony_ci I2S_CKR_TLP_NORMAL | 39362306a36Sopenharmony_ci I2S_CKR_RLP_NORMAL; 39462306a36Sopenharmony_ci break; 39562306a36Sopenharmony_ci case SND_SOC_DAIFMT_IB_IF: 39662306a36Sopenharmony_ci val = I2S_CKR_CKP_INVERTED | 39762306a36Sopenharmony_ci I2S_CKR_TLP_INVERTED | 39862306a36Sopenharmony_ci I2S_CKR_RLP_INVERTED; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci default: 40162306a36Sopenharmony_ci ret = -EINVAL; 40262306a36Sopenharmony_ci goto err_pm_put; 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CKR, mask, val); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 40862306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 40962306a36Sopenharmony_ci txcr_val = I2S_TXCR_IBM_RSJM; 41062306a36Sopenharmony_ci rxcr_val = I2S_RXCR_IBM_RSJM; 41162306a36Sopenharmony_ci break; 41262306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 41362306a36Sopenharmony_ci txcr_val = I2S_TXCR_IBM_LSJM; 41462306a36Sopenharmony_ci rxcr_val = I2S_RXCR_IBM_LSJM; 41562306a36Sopenharmony_ci break; 41662306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 41762306a36Sopenharmony_ci txcr_val = I2S_TXCR_IBM_NORMAL; 41862306a36Sopenharmony_ci rxcr_val = I2S_RXCR_IBM_NORMAL; 41962306a36Sopenharmony_ci break; 42062306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 mode */ 42162306a36Sopenharmony_ci txcr_val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1); 42262306a36Sopenharmony_ci rxcr_val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1); 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */ 42562306a36Sopenharmony_ci txcr_val = I2S_TXCR_TFS_PCM; 42662306a36Sopenharmony_ci rxcr_val = I2S_RXCR_TFS_PCM; 42762306a36Sopenharmony_ci break; 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci ret = -EINVAL; 43062306a36Sopenharmony_ci goto err_pm_put; 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci mask = I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK; 43462306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, txcr_val); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci mask = I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK; 43762306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, rxcr_val); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci if (is_tdm) { 44062306a36Sopenharmony_ci switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { 44162306a36Sopenharmony_ci case SND_SOC_DAIFMT_RIGHT_J: 44262306a36Sopenharmony_ci val = I2S_TXCR_TFS_TDM_I2S; 44362306a36Sopenharmony_ci tdm_val = TDM_SHIFT_CTRL(2); 44462306a36Sopenharmony_ci break; 44562306a36Sopenharmony_ci case SND_SOC_DAIFMT_LEFT_J: 44662306a36Sopenharmony_ci val = I2S_TXCR_TFS_TDM_I2S; 44762306a36Sopenharmony_ci tdm_val = TDM_SHIFT_CTRL(1); 44862306a36Sopenharmony_ci break; 44962306a36Sopenharmony_ci case SND_SOC_DAIFMT_I2S: 45062306a36Sopenharmony_ci val = I2S_TXCR_TFS_TDM_I2S; 45162306a36Sopenharmony_ci tdm_val = TDM_SHIFT_CTRL(0); 45262306a36Sopenharmony_ci break; 45362306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_A: 45462306a36Sopenharmony_ci val = I2S_TXCR_TFS_TDM_PCM; 45562306a36Sopenharmony_ci tdm_val = TDM_SHIFT_CTRL(0); 45662306a36Sopenharmony_ci break; 45762306a36Sopenharmony_ci case SND_SOC_DAIFMT_DSP_B: 45862306a36Sopenharmony_ci val = I2S_TXCR_TFS_TDM_PCM; 45962306a36Sopenharmony_ci tdm_val = TDM_SHIFT_CTRL(2); 46062306a36Sopenharmony_ci break; 46162306a36Sopenharmony_ci default: 46262306a36Sopenharmony_ci ret = -EINVAL; 46362306a36Sopenharmony_ci goto err_pm_put; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci tdm_val |= TDM_FSYNC_WIDTH_SEL1(1); 46762306a36Sopenharmony_ci tdm_val |= TDM_FSYNC_WIDTH_HALF_FRAME; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci mask = I2S_TXCR_TFS_MASK; 47062306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val); 47162306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci mask = TDM_FSYNC_WIDTH_SEL1_MSK | TDM_FSYNC_WIDTH_SEL0_MSK | 47462306a36Sopenharmony_ci TDM_SHIFT_CTRL_MSK; 47562306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TDM_TXCR, 47662306a36Sopenharmony_ci mask, tdm_val); 47762306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR, 47862306a36Sopenharmony_ci mask, tdm_val); 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_cierr_pm_put: 48262306a36Sopenharmony_ci pm_runtime_put(cpu_dai->dev); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void rockchip_i2s_tdm_xfer_pause(struct snd_pcm_substream *substream, 48862306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci int stream; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci stream = SNDRV_PCM_STREAM_LAST - substream->stream; 49362306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) 49462306a36Sopenharmony_ci rockchip_disable_tde(i2s_tdm->regmap); 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci rockchip_disable_rde(i2s_tdm->regmap); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci rockchip_snd_xfer_clear(i2s_tdm, I2S_CLR_TXC | I2S_CLR_RXC); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream, 50262306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm) 50362306a36Sopenharmony_ci{ 50462306a36Sopenharmony_ci int stream; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci stream = SNDRV_PCM_STREAM_LAST - substream->stream; 50762306a36Sopenharmony_ci if (stream == SNDRV_PCM_STREAM_PLAYBACK) 50862306a36Sopenharmony_ci rockchip_enable_tde(i2s_tdm->regmap); 50962306a36Sopenharmony_ci else 51062306a36Sopenharmony_ci rockchip_enable_rde(i2s_tdm->regmap); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_XFER, 51362306a36Sopenharmony_ci I2S_XFER_TXS_START | 51462306a36Sopenharmony_ci I2S_XFER_RXS_START, 51562306a36Sopenharmony_ci I2S_XFER_TXS_START | 51662306a36Sopenharmony_ci I2S_XFER_RXS_START); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int rockchip_i2s_ch_to_io(unsigned int ch, bool substream_capture) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci if (substream_capture) { 52262306a36Sopenharmony_ci switch (ch) { 52362306a36Sopenharmony_ci case I2S_CHN_4: 52462306a36Sopenharmony_ci return I2S_IO_6CH_OUT_4CH_IN; 52562306a36Sopenharmony_ci case I2S_CHN_6: 52662306a36Sopenharmony_ci return I2S_IO_4CH_OUT_6CH_IN; 52762306a36Sopenharmony_ci case I2S_CHN_8: 52862306a36Sopenharmony_ci return I2S_IO_2CH_OUT_8CH_IN; 52962306a36Sopenharmony_ci default: 53062306a36Sopenharmony_ci return I2S_IO_8CH_OUT_2CH_IN; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } else { 53362306a36Sopenharmony_ci switch (ch) { 53462306a36Sopenharmony_ci case I2S_CHN_4: 53562306a36Sopenharmony_ci return I2S_IO_4CH_OUT_6CH_IN; 53662306a36Sopenharmony_ci case I2S_CHN_6: 53762306a36Sopenharmony_ci return I2S_IO_6CH_OUT_4CH_IN; 53862306a36Sopenharmony_ci case I2S_CHN_8: 53962306a36Sopenharmony_ci return I2S_IO_8CH_OUT_2CH_IN; 54062306a36Sopenharmony_ci default: 54162306a36Sopenharmony_ci return I2S_IO_2CH_OUT_8CH_IN; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_cistatic int rockchip_i2s_io_multiplex(struct snd_pcm_substream *substream, 54762306a36Sopenharmony_ci struct snd_soc_dai *dai) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); 55062306a36Sopenharmony_ci int usable_chs = MULTIPLEX_CH_MAX; 55162306a36Sopenharmony_ci unsigned int val = 0; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (!i2s_tdm->io_multiplex) 55462306a36Sopenharmony_ci return 0; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (IS_ERR_OR_NULL(i2s_tdm->grf)) { 55762306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 55862306a36Sopenharmony_ci "io multiplex not supported for this device\n"); 55962306a36Sopenharmony_ci return -EINVAL; 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { 56362306a36Sopenharmony_ci struct snd_pcm_str *playback_str = 56462306a36Sopenharmony_ci &substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK]; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (playback_str->substream_opened) { 56762306a36Sopenharmony_ci regmap_read(i2s_tdm->regmap, I2S_TXCR, &val); 56862306a36Sopenharmony_ci val &= I2S_TXCR_CSR_MASK; 56962306a36Sopenharmony_ci usable_chs = MULTIPLEX_CH_MAX - to_ch_num(val); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci regmap_read(i2s_tdm->regmap, I2S_RXCR, &val); 57362306a36Sopenharmony_ci val &= I2S_RXCR_CSR_MASK; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci if (to_ch_num(val) > usable_chs) { 57662306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 57762306a36Sopenharmony_ci "Capture channels (%d) > usable channels (%d)\n", 57862306a36Sopenharmony_ci to_ch_num(val), usable_chs); 57962306a36Sopenharmony_ci return -EINVAL; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci rockchip_i2s_ch_to_io(val, true); 58362306a36Sopenharmony_ci } else { 58462306a36Sopenharmony_ci struct snd_pcm_str *capture_str = 58562306a36Sopenharmony_ci &substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE]; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (capture_str->substream_opened) { 58862306a36Sopenharmony_ci regmap_read(i2s_tdm->regmap, I2S_RXCR, &val); 58962306a36Sopenharmony_ci val &= I2S_RXCR_CSR_MASK; 59062306a36Sopenharmony_ci usable_chs = MULTIPLEX_CH_MAX - to_ch_num(val); 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci regmap_read(i2s_tdm->regmap, I2S_TXCR, &val); 59462306a36Sopenharmony_ci val &= I2S_TXCR_CSR_MASK; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci if (to_ch_num(val) > usable_chs) { 59762306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 59862306a36Sopenharmony_ci "Playback channels (%d) > usable channels (%d)\n", 59962306a36Sopenharmony_ci to_ch_num(val), usable_chs); 60062306a36Sopenharmony_ci return -EINVAL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci val <<= i2s_tdm->soc_data->grf_shift; 60562306a36Sopenharmony_ci val |= (I2S_IO_DIRECTION_MASK << i2s_tdm->soc_data->grf_shift) << 16; 60662306a36Sopenharmony_ci regmap_write(i2s_tdm->grf, i2s_tdm->soc_data->grf_reg_offset, val); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci return 0; 60962306a36Sopenharmony_ci} 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_cistatic int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream, 61262306a36Sopenharmony_ci struct snd_soc_dai *dai, 61362306a36Sopenharmony_ci unsigned int div_bclk, 61462306a36Sopenharmony_ci unsigned int div_lrck, 61562306a36Sopenharmony_ci unsigned int fmt) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); 61862306a36Sopenharmony_ci unsigned long flags; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (!i2s_tdm->clk_trcm) 62162306a36Sopenharmony_ci return 0; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci spin_lock_irqsave(&i2s_tdm->lock, flags); 62462306a36Sopenharmony_ci if (i2s_tdm->refcount) 62562306a36Sopenharmony_ci rockchip_i2s_tdm_xfer_pause(substream, i2s_tdm); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV, 62862306a36Sopenharmony_ci I2S_CLKDIV_TXM_MASK | I2S_CLKDIV_RXM_MASK, 62962306a36Sopenharmony_ci I2S_CLKDIV_TXM(div_bclk) | I2S_CLKDIV_RXM(div_bclk)); 63062306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CKR, 63162306a36Sopenharmony_ci I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK, 63262306a36Sopenharmony_ci I2S_CKR_TSD(div_lrck) | I2S_CKR_RSD(div_lrck)); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 63562306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, 63662306a36Sopenharmony_ci I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, 63762306a36Sopenharmony_ci fmt); 63862306a36Sopenharmony_ci else 63962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, 64062306a36Sopenharmony_ci I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK, 64162306a36Sopenharmony_ci fmt); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (i2s_tdm->refcount) 64462306a36Sopenharmony_ci rockchip_i2s_tdm_xfer_resume(substream, i2s_tdm); 64562306a36Sopenharmony_ci spin_unlock_irqrestore(&i2s_tdm->lock, flags); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci return 0; 64862306a36Sopenharmony_ci} 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cistatic int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream, 65162306a36Sopenharmony_ci struct snd_pcm_hw_params *params, 65262306a36Sopenharmony_ci struct snd_soc_dai *dai) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); 65562306a36Sopenharmony_ci unsigned int val = 0; 65662306a36Sopenharmony_ci unsigned int mclk_rate, bclk_rate, div_bclk = 4, div_lrck = 64; 65762306a36Sopenharmony_ci int err; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (i2s_tdm->is_master_mode) { 66062306a36Sopenharmony_ci struct clk *mclk = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ? 66162306a36Sopenharmony_ci i2s_tdm->mclk_tx : i2s_tdm->mclk_rx; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci err = clk_set_rate(mclk, DEFAULT_MCLK_FS * params_rate(params)); 66462306a36Sopenharmony_ci if (err) 66562306a36Sopenharmony_ci return err; 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci mclk_rate = clk_get_rate(mclk); 66862306a36Sopenharmony_ci bclk_rate = i2s_tdm->frame_width * params_rate(params); 66962306a36Sopenharmony_ci if (!bclk_rate) 67062306a36Sopenharmony_ci return -EINVAL; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate); 67362306a36Sopenharmony_ci div_lrck = bclk_rate / params_rate(params); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci switch (params_format(params)) { 67762306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S8: 67862306a36Sopenharmony_ci val |= I2S_TXCR_VDW(8); 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 68162306a36Sopenharmony_ci val |= I2S_TXCR_VDW(16); 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 68462306a36Sopenharmony_ci val |= I2S_TXCR_VDW(20); 68562306a36Sopenharmony_ci break; 68662306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 68762306a36Sopenharmony_ci val |= I2S_TXCR_VDW(24); 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci case SNDRV_PCM_FORMAT_S32_LE: 69062306a36Sopenharmony_ci val |= I2S_TXCR_VDW(32); 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci default: 69362306a36Sopenharmony_ci return -EINVAL; 69462306a36Sopenharmony_ci } 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci switch (params_channels(params)) { 69762306a36Sopenharmony_ci case 8: 69862306a36Sopenharmony_ci val |= I2S_CHN_8; 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci case 6: 70162306a36Sopenharmony_ci val |= I2S_CHN_6; 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci case 4: 70462306a36Sopenharmony_ci val |= I2S_CHN_4; 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci case 2: 70762306a36Sopenharmony_ci val |= I2S_CHN_2; 70862306a36Sopenharmony_ci break; 70962306a36Sopenharmony_ci default: 71062306a36Sopenharmony_ci return -EINVAL; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci if (i2s_tdm->clk_trcm) { 71462306a36Sopenharmony_ci rockchip_i2s_trcm_mode(substream, dai, div_bclk, div_lrck, val); 71562306a36Sopenharmony_ci } else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 71662306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV, 71762306a36Sopenharmony_ci I2S_CLKDIV_TXM_MASK, 71862306a36Sopenharmony_ci I2S_CLKDIV_TXM(div_bclk)); 71962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CKR, 72062306a36Sopenharmony_ci I2S_CKR_TSD_MASK, 72162306a36Sopenharmony_ci I2S_CKR_TSD(div_lrck)); 72262306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, 72362306a36Sopenharmony_ci I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK, 72462306a36Sopenharmony_ci val); 72562306a36Sopenharmony_ci } else { 72662306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV, 72762306a36Sopenharmony_ci I2S_CLKDIV_RXM_MASK, 72862306a36Sopenharmony_ci I2S_CLKDIV_RXM(div_bclk)); 72962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CKR, 73062306a36Sopenharmony_ci I2S_CKR_RSD_MASK, 73162306a36Sopenharmony_ci I2S_CKR_RSD(div_lrck)); 73262306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, 73362306a36Sopenharmony_ci I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK, 73462306a36Sopenharmony_ci val); 73562306a36Sopenharmony_ci } 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci return rockchip_i2s_io_multiplex(substream, dai); 73862306a36Sopenharmony_ci} 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream, 74162306a36Sopenharmony_ci int cmd, struct snd_soc_dai *dai) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci switch (cmd) { 74662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 74762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 74862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 74962306a36Sopenharmony_ci if (i2s_tdm->clk_trcm) 75062306a36Sopenharmony_ci rockchip_snd_txrxctrl(substream, dai, 1); 75162306a36Sopenharmony_ci else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 75262306a36Sopenharmony_ci rockchip_snd_rxctrl(i2s_tdm, 1); 75362306a36Sopenharmony_ci else 75462306a36Sopenharmony_ci rockchip_snd_txctrl(i2s_tdm, 1); 75562306a36Sopenharmony_ci break; 75662306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 75762306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 75862306a36Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 75962306a36Sopenharmony_ci if (i2s_tdm->clk_trcm) 76062306a36Sopenharmony_ci rockchip_snd_txrxctrl(substream, dai, 0); 76162306a36Sopenharmony_ci else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) 76262306a36Sopenharmony_ci rockchip_snd_rxctrl(i2s_tdm, 0); 76362306a36Sopenharmony_ci else 76462306a36Sopenharmony_ci rockchip_snd_txctrl(i2s_tdm, 0); 76562306a36Sopenharmony_ci break; 76662306a36Sopenharmony_ci default: 76762306a36Sopenharmony_ci return -EINVAL; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci return 0; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_cistatic int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai) 77462306a36Sopenharmony_ci{ 77562306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (i2s_tdm->has_capture) 77862306a36Sopenharmony_ci snd_soc_dai_dma_data_set_capture(dai, &i2s_tdm->capture_dma_data); 77962306a36Sopenharmony_ci if (i2s_tdm->has_playback) 78062306a36Sopenharmony_ci snd_soc_dai_dma_data_set_playback(dai, &i2s_tdm->playback_dma_data); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int rockchip_dai_tdm_slot(struct snd_soc_dai *dai, 78662306a36Sopenharmony_ci unsigned int tx_mask, unsigned int rx_mask, 78762306a36Sopenharmony_ci int slots, int slot_width) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); 79062306a36Sopenharmony_ci unsigned int mask, val; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci i2s_tdm->tdm_mode = true; 79362306a36Sopenharmony_ci i2s_tdm->frame_width = slots * slot_width; 79462306a36Sopenharmony_ci mask = TDM_SLOT_BIT_WIDTH_MSK | TDM_FRAME_WIDTH_MSK; 79562306a36Sopenharmony_ci val = TDM_SLOT_BIT_WIDTH(slot_width) | 79662306a36Sopenharmony_ci TDM_FRAME_WIDTH(slots * slot_width); 79762306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TDM_TXCR, 79862306a36Sopenharmony_ci mask, val); 79962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR, 80062306a36Sopenharmony_ci mask, val); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return 0; 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_cistatic int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai, 80662306a36Sopenharmony_ci unsigned int ratio) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (ratio < 32 || ratio > 512 || ratio % 2 == 1) 81162306a36Sopenharmony_ci return -EINVAL; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci i2s_tdm->frame_width = ratio; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci return 0; 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = { 81962306a36Sopenharmony_ci .probe = rockchip_i2s_tdm_dai_probe, 82062306a36Sopenharmony_ci .hw_params = rockchip_i2s_tdm_hw_params, 82162306a36Sopenharmony_ci .set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio, 82262306a36Sopenharmony_ci .set_fmt = rockchip_i2s_tdm_set_fmt, 82362306a36Sopenharmony_ci .set_tdm_slot = rockchip_dai_tdm_slot, 82462306a36Sopenharmony_ci .trigger = rockchip_i2s_tdm_trigger, 82562306a36Sopenharmony_ci}; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_cistatic const struct snd_soc_component_driver rockchip_i2s_tdm_component = { 82862306a36Sopenharmony_ci .name = DRV_NAME, 82962306a36Sopenharmony_ci .legacy_dai_naming = 1, 83062306a36Sopenharmony_ci}; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci switch (reg) { 83562306a36Sopenharmony_ci case I2S_TXCR: 83662306a36Sopenharmony_ci case I2S_RXCR: 83762306a36Sopenharmony_ci case I2S_CKR: 83862306a36Sopenharmony_ci case I2S_DMACR: 83962306a36Sopenharmony_ci case I2S_INTCR: 84062306a36Sopenharmony_ci case I2S_XFER: 84162306a36Sopenharmony_ci case I2S_CLR: 84262306a36Sopenharmony_ci case I2S_TXDR: 84362306a36Sopenharmony_ci case I2S_TDM_TXCR: 84462306a36Sopenharmony_ci case I2S_TDM_RXCR: 84562306a36Sopenharmony_ci case I2S_CLKDIV: 84662306a36Sopenharmony_ci return true; 84762306a36Sopenharmony_ci default: 84862306a36Sopenharmony_ci return false; 84962306a36Sopenharmony_ci } 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_cistatic bool rockchip_i2s_tdm_rd_reg(struct device *dev, unsigned int reg) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci switch (reg) { 85562306a36Sopenharmony_ci case I2S_TXCR: 85662306a36Sopenharmony_ci case I2S_RXCR: 85762306a36Sopenharmony_ci case I2S_CKR: 85862306a36Sopenharmony_ci case I2S_DMACR: 85962306a36Sopenharmony_ci case I2S_INTCR: 86062306a36Sopenharmony_ci case I2S_XFER: 86162306a36Sopenharmony_ci case I2S_CLR: 86262306a36Sopenharmony_ci case I2S_TXDR: 86362306a36Sopenharmony_ci case I2S_RXDR: 86462306a36Sopenharmony_ci case I2S_TXFIFOLR: 86562306a36Sopenharmony_ci case I2S_INTSR: 86662306a36Sopenharmony_ci case I2S_RXFIFOLR: 86762306a36Sopenharmony_ci case I2S_TDM_TXCR: 86862306a36Sopenharmony_ci case I2S_TDM_RXCR: 86962306a36Sopenharmony_ci case I2S_CLKDIV: 87062306a36Sopenharmony_ci return true; 87162306a36Sopenharmony_ci default: 87262306a36Sopenharmony_ci return false; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci} 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_cistatic bool rockchip_i2s_tdm_volatile_reg(struct device *dev, unsigned int reg) 87762306a36Sopenharmony_ci{ 87862306a36Sopenharmony_ci switch (reg) { 87962306a36Sopenharmony_ci case I2S_TXFIFOLR: 88062306a36Sopenharmony_ci case I2S_INTSR: 88162306a36Sopenharmony_ci case I2S_CLR: 88262306a36Sopenharmony_ci case I2S_TXDR: 88362306a36Sopenharmony_ci case I2S_RXDR: 88462306a36Sopenharmony_ci case I2S_RXFIFOLR: 88562306a36Sopenharmony_ci return true; 88662306a36Sopenharmony_ci default: 88762306a36Sopenharmony_ci return false; 88862306a36Sopenharmony_ci } 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic bool rockchip_i2s_tdm_precious_reg(struct device *dev, unsigned int reg) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci if (reg == I2S_RXDR) 89462306a36Sopenharmony_ci return true; 89562306a36Sopenharmony_ci return false; 89662306a36Sopenharmony_ci} 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_cistatic const struct reg_default rockchip_i2s_tdm_reg_defaults[] = { 89962306a36Sopenharmony_ci {0x00, 0x7200000f}, 90062306a36Sopenharmony_ci {0x04, 0x01c8000f}, 90162306a36Sopenharmony_ci {0x08, 0x00001f1f}, 90262306a36Sopenharmony_ci {0x10, 0x001f0000}, 90362306a36Sopenharmony_ci {0x14, 0x01f00000}, 90462306a36Sopenharmony_ci {0x30, 0x00003eff}, 90562306a36Sopenharmony_ci {0x34, 0x00003eff}, 90662306a36Sopenharmony_ci {0x38, 0x00000707}, 90762306a36Sopenharmony_ci}; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic const struct regmap_config rockchip_i2s_tdm_regmap_config = { 91062306a36Sopenharmony_ci .reg_bits = 32, 91162306a36Sopenharmony_ci .reg_stride = 4, 91262306a36Sopenharmony_ci .val_bits = 32, 91362306a36Sopenharmony_ci .max_register = I2S_CLKDIV, 91462306a36Sopenharmony_ci .reg_defaults = rockchip_i2s_tdm_reg_defaults, 91562306a36Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(rockchip_i2s_tdm_reg_defaults), 91662306a36Sopenharmony_ci .writeable_reg = rockchip_i2s_tdm_wr_reg, 91762306a36Sopenharmony_ci .readable_reg = rockchip_i2s_tdm_rd_reg, 91862306a36Sopenharmony_ci .volatile_reg = rockchip_i2s_tdm_volatile_reg, 91962306a36Sopenharmony_ci .precious_reg = rockchip_i2s_tdm_precious_reg, 92062306a36Sopenharmony_ci .cache_type = REGCACHE_FLAT, 92162306a36Sopenharmony_ci}; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic int common_soc_init(struct device *dev, u32 addr) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); 92662306a36Sopenharmony_ci const struct txrx_config *configs = i2s_tdm->soc_data->configs; 92762306a36Sopenharmony_ci u32 reg = 0, val = 0, trcm = i2s_tdm->clk_trcm; 92862306a36Sopenharmony_ci int i; 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci if (trcm == TRCM_TXRX) 93162306a36Sopenharmony_ci return 0; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (IS_ERR_OR_NULL(i2s_tdm->grf)) { 93462306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 93562306a36Sopenharmony_ci "no grf present but non-txrx TRCM specified\n"); 93662306a36Sopenharmony_ci return -EINVAL; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci for (i = 0; i < i2s_tdm->soc_data->config_count; i++) { 94062306a36Sopenharmony_ci if (addr != configs[i].addr) 94162306a36Sopenharmony_ci continue; 94262306a36Sopenharmony_ci reg = configs[i].reg; 94362306a36Sopenharmony_ci if (trcm == TRCM_TX) 94462306a36Sopenharmony_ci val = configs[i].txonly; 94562306a36Sopenharmony_ci else 94662306a36Sopenharmony_ci val = configs[i].rxonly; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (reg) 94962306a36Sopenharmony_ci regmap_write(i2s_tdm->grf, reg, val); 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return 0; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_cistatic const struct txrx_config px30_txrx_config[] = { 95662306a36Sopenharmony_ci { 0xff060000, 0x184, PX30_I2S0_CLK_TXONLY, PX30_I2S0_CLK_RXONLY }, 95762306a36Sopenharmony_ci}; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic const struct txrx_config rk1808_txrx_config[] = { 96062306a36Sopenharmony_ci { 0xff7e0000, 0x190, RK1808_I2S0_CLK_TXONLY, RK1808_I2S0_CLK_RXONLY }, 96162306a36Sopenharmony_ci}; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_cistatic const struct txrx_config rk3308_txrx_config[] = { 96462306a36Sopenharmony_ci { 0xff300000, 0x308, RK3308_I2S0_CLK_TXONLY, RK3308_I2S0_CLK_RXONLY }, 96562306a36Sopenharmony_ci { 0xff310000, 0x308, RK3308_I2S1_CLK_TXONLY, RK3308_I2S1_CLK_RXONLY }, 96662306a36Sopenharmony_ci}; 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_cistatic const struct txrx_config rk3568_txrx_config[] = { 96962306a36Sopenharmony_ci { 0xfe410000, 0x504, RK3568_I2S1_CLK_TXONLY, RK3568_I2S1_CLK_RXONLY }, 97062306a36Sopenharmony_ci { 0xfe410000, 0x508, RK3568_I2S1_MCLK_TX_OE, RK3568_I2S1_MCLK_RX_OE }, 97162306a36Sopenharmony_ci { 0xfe420000, 0x508, RK3568_I2S2_MCLK_OE, RK3568_I2S2_MCLK_OE }, 97262306a36Sopenharmony_ci { 0xfe430000, 0x504, RK3568_I2S3_CLK_TXONLY, RK3568_I2S3_CLK_RXONLY }, 97362306a36Sopenharmony_ci { 0xfe430000, 0x508, RK3568_I2S3_MCLK_TXONLY, RK3568_I2S3_MCLK_RXONLY }, 97462306a36Sopenharmony_ci { 0xfe430000, 0x508, RK3568_I2S3_MCLK_OE, RK3568_I2S3_MCLK_OE }, 97562306a36Sopenharmony_ci}; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_cistatic const struct txrx_config rv1126_txrx_config[] = { 97862306a36Sopenharmony_ci { 0xff800000, 0x10260, RV1126_I2S0_CLK_TXONLY, RV1126_I2S0_CLK_RXONLY }, 97962306a36Sopenharmony_ci}; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_cistatic struct rk_i2s_soc_data px30_i2s_soc_data = { 98262306a36Sopenharmony_ci .softrst_offset = 0x0300, 98362306a36Sopenharmony_ci .configs = px30_txrx_config, 98462306a36Sopenharmony_ci .config_count = ARRAY_SIZE(px30_txrx_config), 98562306a36Sopenharmony_ci .init = common_soc_init, 98662306a36Sopenharmony_ci}; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_cistatic struct rk_i2s_soc_data rk1808_i2s_soc_data = { 98962306a36Sopenharmony_ci .softrst_offset = 0x0300, 99062306a36Sopenharmony_ci .configs = rk1808_txrx_config, 99162306a36Sopenharmony_ci .config_count = ARRAY_SIZE(rk1808_txrx_config), 99262306a36Sopenharmony_ci .init = common_soc_init, 99362306a36Sopenharmony_ci}; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_cistatic struct rk_i2s_soc_data rk3308_i2s_soc_data = { 99662306a36Sopenharmony_ci .softrst_offset = 0x0400, 99762306a36Sopenharmony_ci .grf_reg_offset = 0x0308, 99862306a36Sopenharmony_ci .grf_shift = 5, 99962306a36Sopenharmony_ci .configs = rk3308_txrx_config, 100062306a36Sopenharmony_ci .config_count = ARRAY_SIZE(rk3308_txrx_config), 100162306a36Sopenharmony_ci .init = common_soc_init, 100262306a36Sopenharmony_ci}; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_cistatic struct rk_i2s_soc_data rk3568_i2s_soc_data = { 100562306a36Sopenharmony_ci .softrst_offset = 0x0400, 100662306a36Sopenharmony_ci .configs = rk3568_txrx_config, 100762306a36Sopenharmony_ci .config_count = ARRAY_SIZE(rk3568_txrx_config), 100862306a36Sopenharmony_ci .init = common_soc_init, 100962306a36Sopenharmony_ci}; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic struct rk_i2s_soc_data rv1126_i2s_soc_data = { 101262306a36Sopenharmony_ci .softrst_offset = 0x0300, 101362306a36Sopenharmony_ci .configs = rv1126_txrx_config, 101462306a36Sopenharmony_ci .config_count = ARRAY_SIZE(rv1126_txrx_config), 101562306a36Sopenharmony_ci .init = common_soc_init, 101662306a36Sopenharmony_ci}; 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic const struct of_device_id rockchip_i2s_tdm_match[] = { 101962306a36Sopenharmony_ci { .compatible = "rockchip,px30-i2s-tdm", .data = &px30_i2s_soc_data }, 102062306a36Sopenharmony_ci { .compatible = "rockchip,rk1808-i2s-tdm", .data = &rk1808_i2s_soc_data }, 102162306a36Sopenharmony_ci { .compatible = "rockchip,rk3308-i2s-tdm", .data = &rk3308_i2s_soc_data }, 102262306a36Sopenharmony_ci { .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data }, 102362306a36Sopenharmony_ci { .compatible = "rockchip,rk3588-i2s-tdm" }, 102462306a36Sopenharmony_ci { .compatible = "rockchip,rv1126-i2s-tdm", .data = &rv1126_i2s_soc_data }, 102562306a36Sopenharmony_ci {}, 102662306a36Sopenharmony_ci}; 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic const struct snd_soc_dai_driver i2s_tdm_dai = { 102962306a36Sopenharmony_ci .ops = &rockchip_i2s_tdm_dai_ops, 103062306a36Sopenharmony_ci}; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_cistatic int rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm) 103362306a36Sopenharmony_ci{ 103462306a36Sopenharmony_ci struct snd_soc_dai_driver *dai; 103562306a36Sopenharmony_ci struct property *dma_names; 103662306a36Sopenharmony_ci const char *dma_name; 103762306a36Sopenharmony_ci u64 formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE | 103862306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE | 103962306a36Sopenharmony_ci SNDRV_PCM_FMTBIT_S32_LE); 104062306a36Sopenharmony_ci struct device_node *node = i2s_tdm->dev->of_node; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci of_property_for_each_string(node, "dma-names", dma_names, dma_name) { 104362306a36Sopenharmony_ci if (!strcmp(dma_name, "tx")) 104462306a36Sopenharmony_ci i2s_tdm->has_playback = true; 104562306a36Sopenharmony_ci if (!strcmp(dma_name, "rx")) 104662306a36Sopenharmony_ci i2s_tdm->has_capture = true; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_ci dai = devm_kmemdup(i2s_tdm->dev, &i2s_tdm_dai, 105062306a36Sopenharmony_ci sizeof(*dai), GFP_KERNEL); 105162306a36Sopenharmony_ci if (!dai) 105262306a36Sopenharmony_ci return -ENOMEM; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci if (i2s_tdm->has_playback) { 105562306a36Sopenharmony_ci dai->playback.stream_name = "Playback"; 105662306a36Sopenharmony_ci dai->playback.channels_min = 2; 105762306a36Sopenharmony_ci dai->playback.channels_max = 8; 105862306a36Sopenharmony_ci dai->playback.rates = SNDRV_PCM_RATE_8000_192000; 105962306a36Sopenharmony_ci dai->playback.formats = formats; 106062306a36Sopenharmony_ci } 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (i2s_tdm->has_capture) { 106362306a36Sopenharmony_ci dai->capture.stream_name = "Capture"; 106462306a36Sopenharmony_ci dai->capture.channels_min = 2; 106562306a36Sopenharmony_ci dai->capture.channels_max = 8; 106662306a36Sopenharmony_ci dai->capture.rates = SNDRV_PCM_RATE_8000_192000; 106762306a36Sopenharmony_ci dai->capture.formats = formats; 106862306a36Sopenharmony_ci } 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_ci if (i2s_tdm->clk_trcm != TRCM_TXRX) 107162306a36Sopenharmony_ci dai->symmetric_rate = 1; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci i2s_tdm->dai = dai; 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return 0; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_cistatic int rockchip_i2s_tdm_path_check(struct rk_i2s_tdm_dev *i2s_tdm, 107962306a36Sopenharmony_ci int num, 108062306a36Sopenharmony_ci bool is_rx_path) 108162306a36Sopenharmony_ci{ 108262306a36Sopenharmony_ci unsigned int *i2s_data; 108362306a36Sopenharmony_ci int i, j; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (is_rx_path) 108662306a36Sopenharmony_ci i2s_data = i2s_tdm->i2s_sdis; 108762306a36Sopenharmony_ci else 108862306a36Sopenharmony_ci i2s_data = i2s_tdm->i2s_sdos; 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci for (i = 0; i < num; i++) { 109162306a36Sopenharmony_ci if (i2s_data[i] > CH_GRP_MAX - 1) { 109262306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 109362306a36Sopenharmony_ci "%s path i2s_data[%d]: %d is too high, max is: %d\n", 109462306a36Sopenharmony_ci is_rx_path ? "RX" : "TX", 109562306a36Sopenharmony_ci i, i2s_data[i], CH_GRP_MAX); 109662306a36Sopenharmony_ci return -EINVAL; 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci for (j = 0; j < num; j++) { 110062306a36Sopenharmony_ci if (i == j) 110162306a36Sopenharmony_ci continue; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci if (i2s_data[i] == i2s_data[j]) { 110462306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 110562306a36Sopenharmony_ci "%s path invalid routed i2s_data: [%d]%d == [%d]%d\n", 110662306a36Sopenharmony_ci is_rx_path ? "RX" : "TX", 110762306a36Sopenharmony_ci i, i2s_data[i], 110862306a36Sopenharmony_ci j, i2s_data[j]); 110962306a36Sopenharmony_ci return -EINVAL; 111062306a36Sopenharmony_ci } 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci } 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_ci return 0; 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic void rockchip_i2s_tdm_tx_path_config(struct rk_i2s_tdm_dev *i2s_tdm, 111862306a36Sopenharmony_ci int num) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci int idx; 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_ci for (idx = 0; idx < num; idx++) { 112362306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, 112462306a36Sopenharmony_ci I2S_TXCR_PATH_MASK(idx), 112562306a36Sopenharmony_ci I2S_TXCR_PATH(idx, i2s_tdm->i2s_sdos[idx])); 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic void rockchip_i2s_tdm_rx_path_config(struct rk_i2s_tdm_dev *i2s_tdm, 113062306a36Sopenharmony_ci int num) 113162306a36Sopenharmony_ci{ 113262306a36Sopenharmony_ci int idx; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci for (idx = 0; idx < num; idx++) { 113562306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, 113662306a36Sopenharmony_ci I2S_RXCR_PATH_MASK(idx), 113762306a36Sopenharmony_ci I2S_RXCR_PATH(idx, i2s_tdm->i2s_sdis[idx])); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_cistatic void rockchip_i2s_tdm_path_config(struct rk_i2s_tdm_dev *i2s_tdm, 114262306a36Sopenharmony_ci int num, bool is_rx_path) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci if (is_rx_path) 114562306a36Sopenharmony_ci rockchip_i2s_tdm_rx_path_config(i2s_tdm, num); 114662306a36Sopenharmony_ci else 114762306a36Sopenharmony_ci rockchip_i2s_tdm_tx_path_config(i2s_tdm, num); 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic int rockchip_i2s_tdm_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm, 115162306a36Sopenharmony_ci struct device_node *np, 115262306a36Sopenharmony_ci bool is_rx_path) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci char *i2s_tx_path_prop = "rockchip,i2s-tx-route"; 115562306a36Sopenharmony_ci char *i2s_rx_path_prop = "rockchip,i2s-rx-route"; 115662306a36Sopenharmony_ci char *i2s_path_prop; 115762306a36Sopenharmony_ci unsigned int *i2s_data; 115862306a36Sopenharmony_ci int num, ret = 0; 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci if (is_rx_path) { 116162306a36Sopenharmony_ci i2s_path_prop = i2s_rx_path_prop; 116262306a36Sopenharmony_ci i2s_data = i2s_tdm->i2s_sdis; 116362306a36Sopenharmony_ci } else { 116462306a36Sopenharmony_ci i2s_path_prop = i2s_tx_path_prop; 116562306a36Sopenharmony_ci i2s_data = i2s_tdm->i2s_sdos; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci num = of_count_phandle_with_args(np, i2s_path_prop, NULL); 116962306a36Sopenharmony_ci if (num < 0) { 117062306a36Sopenharmony_ci if (num != -ENOENT) { 117162306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 117262306a36Sopenharmony_ci "Failed to read '%s' num: %d\n", 117362306a36Sopenharmony_ci i2s_path_prop, num); 117462306a36Sopenharmony_ci ret = num; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci return ret; 117762306a36Sopenharmony_ci } else if (num != CH_GRP_MAX) { 117862306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 117962306a36Sopenharmony_ci "The num: %d should be: %d\n", num, CH_GRP_MAX); 118062306a36Sopenharmony_ci return -EINVAL; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci ret = of_property_read_u32_array(np, i2s_path_prop, 118462306a36Sopenharmony_ci i2s_data, num); 118562306a36Sopenharmony_ci if (ret < 0) { 118662306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 118762306a36Sopenharmony_ci "Failed to read '%s': %d\n", 118862306a36Sopenharmony_ci i2s_path_prop, ret); 118962306a36Sopenharmony_ci return ret; 119062306a36Sopenharmony_ci } 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci ret = rockchip_i2s_tdm_path_check(i2s_tdm, num, is_rx_path); 119362306a36Sopenharmony_ci if (ret < 0) { 119462306a36Sopenharmony_ci dev_err(i2s_tdm->dev, 119562306a36Sopenharmony_ci "Failed to check i2s data bus: %d\n", ret); 119662306a36Sopenharmony_ci return ret; 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci rockchip_i2s_tdm_path_config(i2s_tdm, num, is_rx_path); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci return 0; 120262306a36Sopenharmony_ci} 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_cistatic int rockchip_i2s_tdm_tx_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm, 120562306a36Sopenharmony_ci struct device_node *np) 120662306a36Sopenharmony_ci{ 120762306a36Sopenharmony_ci return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 0); 120862306a36Sopenharmony_ci} 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_cistatic int rockchip_i2s_tdm_rx_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm, 121162306a36Sopenharmony_ci struct device_node *np) 121262306a36Sopenharmony_ci{ 121362306a36Sopenharmony_ci return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 1); 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic int rockchip_i2s_tdm_probe(struct platform_device *pdev) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 121962306a36Sopenharmony_ci const struct of_device_id *of_id; 122062306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm; 122162306a36Sopenharmony_ci struct resource *res; 122262306a36Sopenharmony_ci void __iomem *regs; 122362306a36Sopenharmony_ci int ret; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci i2s_tdm = devm_kzalloc(&pdev->dev, sizeof(*i2s_tdm), GFP_KERNEL); 122662306a36Sopenharmony_ci if (!i2s_tdm) 122762306a36Sopenharmony_ci return -ENOMEM; 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci i2s_tdm->dev = &pdev->dev; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci of_id = of_match_device(rockchip_i2s_tdm_match, &pdev->dev); 123262306a36Sopenharmony_ci if (!of_id) 123362306a36Sopenharmony_ci return -EINVAL; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci spin_lock_init(&i2s_tdm->lock); 123662306a36Sopenharmony_ci i2s_tdm->soc_data = (struct rk_i2s_soc_data *)of_id->data; 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci i2s_tdm->frame_width = 64; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci i2s_tdm->clk_trcm = TRCM_TXRX; 124162306a36Sopenharmony_ci if (of_property_read_bool(node, "rockchip,trcm-sync-tx-only")) 124262306a36Sopenharmony_ci i2s_tdm->clk_trcm = TRCM_TX; 124362306a36Sopenharmony_ci if (of_property_read_bool(node, "rockchip,trcm-sync-rx-only")) { 124462306a36Sopenharmony_ci if (i2s_tdm->clk_trcm) { 124562306a36Sopenharmony_ci dev_err(i2s_tdm->dev, "invalid trcm-sync configuration\n"); 124662306a36Sopenharmony_ci return -EINVAL; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci i2s_tdm->clk_trcm = TRCM_RX; 124962306a36Sopenharmony_ci } 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_ci ret = rockchip_i2s_tdm_init_dai(i2s_tdm); 125262306a36Sopenharmony_ci if (ret) 125362306a36Sopenharmony_ci return ret; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_ci i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf"); 125662306a36Sopenharmony_ci i2s_tdm->tx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev, 125762306a36Sopenharmony_ci "tx-m"); 125862306a36Sopenharmony_ci if (IS_ERR(i2s_tdm->tx_reset)) { 125962306a36Sopenharmony_ci ret = PTR_ERR(i2s_tdm->tx_reset); 126062306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, ret, 126162306a36Sopenharmony_ci "Error in tx-m reset control\n"); 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci i2s_tdm->rx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev, 126562306a36Sopenharmony_ci "rx-m"); 126662306a36Sopenharmony_ci if (IS_ERR(i2s_tdm->rx_reset)) { 126762306a36Sopenharmony_ci ret = PTR_ERR(i2s_tdm->rx_reset); 126862306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, ret, 126962306a36Sopenharmony_ci "Error in rx-m reset control\n"); 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci i2s_tdm->hclk = devm_clk_get(&pdev->dev, "hclk"); 127362306a36Sopenharmony_ci if (IS_ERR(i2s_tdm->hclk)) { 127462306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->hclk), 127562306a36Sopenharmony_ci "Failed to get clock hclk\n"); 127662306a36Sopenharmony_ci } 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci i2s_tdm->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx"); 127962306a36Sopenharmony_ci if (IS_ERR(i2s_tdm->mclk_tx)) { 128062306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->mclk_tx), 128162306a36Sopenharmony_ci "Failed to get clock mclk_tx\n"); 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci i2s_tdm->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx"); 128562306a36Sopenharmony_ci if (IS_ERR(i2s_tdm->mclk_rx)) { 128662306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->mclk_rx), 128762306a36Sopenharmony_ci "Failed to get clock mclk_rx\n"); 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci i2s_tdm->io_multiplex = 129162306a36Sopenharmony_ci of_property_read_bool(node, "rockchip,io-multiplex"); 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 129462306a36Sopenharmony_ci if (IS_ERR(regs)) { 129562306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, PTR_ERR(regs), 129662306a36Sopenharmony_ci "Failed to get resource IORESOURCE_MEM\n"); 129762306a36Sopenharmony_ci } 129862306a36Sopenharmony_ci 129962306a36Sopenharmony_ci i2s_tdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs, 130062306a36Sopenharmony_ci &rockchip_i2s_tdm_regmap_config); 130162306a36Sopenharmony_ci if (IS_ERR(i2s_tdm->regmap)) { 130262306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->regmap), 130362306a36Sopenharmony_ci "Failed to initialise regmap\n"); 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (i2s_tdm->has_playback) { 130762306a36Sopenharmony_ci i2s_tdm->playback_dma_data.addr = res->start + I2S_TXDR; 130862306a36Sopenharmony_ci i2s_tdm->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 130962306a36Sopenharmony_ci i2s_tdm->playback_dma_data.maxburst = 8; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci 131262306a36Sopenharmony_ci if (i2s_tdm->has_capture) { 131362306a36Sopenharmony_ci i2s_tdm->capture_dma_data.addr = res->start + I2S_RXDR; 131462306a36Sopenharmony_ci i2s_tdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 131562306a36Sopenharmony_ci i2s_tdm->capture_dma_data.maxburst = 8; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci ret = rockchip_i2s_tdm_tx_path_prepare(i2s_tdm, node); 131962306a36Sopenharmony_ci if (ret < 0) { 132062306a36Sopenharmony_ci dev_err(&pdev->dev, "I2S TX path prepare failed: %d\n", ret); 132162306a36Sopenharmony_ci return ret; 132262306a36Sopenharmony_ci } 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci ret = rockchip_i2s_tdm_rx_path_prepare(i2s_tdm, node); 132562306a36Sopenharmony_ci if (ret < 0) { 132662306a36Sopenharmony_ci dev_err(&pdev->dev, "I2S RX path prepare failed: %d\n", ret); 132762306a36Sopenharmony_ci return ret; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci dev_set_drvdata(&pdev->dev, i2s_tdm); 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci ret = clk_prepare_enable(i2s_tdm->hclk); 133362306a36Sopenharmony_ci if (ret) { 133462306a36Sopenharmony_ci return dev_err_probe(i2s_tdm->dev, ret, 133562306a36Sopenharmony_ci "Failed to enable clock hclk\n"); 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci ret = i2s_tdm_prepare_enable_mclk(i2s_tdm); 133962306a36Sopenharmony_ci if (ret) { 134062306a36Sopenharmony_ci ret = dev_err_probe(i2s_tdm->dev, ret, 134162306a36Sopenharmony_ci "Failed to enable one or more mclks\n"); 134262306a36Sopenharmony_ci goto err_disable_hclk; 134362306a36Sopenharmony_ci } 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK, 134862306a36Sopenharmony_ci I2S_DMACR_TDL(16)); 134962306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK, 135062306a36Sopenharmony_ci I2S_DMACR_RDL(16)); 135162306a36Sopenharmony_ci regmap_update_bits(i2s_tdm->regmap, I2S_CKR, I2S_CKR_TRCM_MASK, 135262306a36Sopenharmony_ci i2s_tdm->clk_trcm << I2S_CKR_TRCM_SHIFT); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci if (i2s_tdm->soc_data && i2s_tdm->soc_data->init) 135562306a36Sopenharmony_ci i2s_tdm->soc_data->init(&pdev->dev, res->start); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, 135862306a36Sopenharmony_ci &rockchip_i2s_tdm_component, 135962306a36Sopenharmony_ci i2s_tdm->dai, 1); 136062306a36Sopenharmony_ci 136162306a36Sopenharmony_ci if (ret) { 136262306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not register DAI\n"); 136362306a36Sopenharmony_ci goto err_suspend; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 136762306a36Sopenharmony_ci if (ret) { 136862306a36Sopenharmony_ci dev_err(&pdev->dev, "Could not register PCM\n"); 136962306a36Sopenharmony_ci goto err_suspend; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci return 0; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_cierr_suspend: 137562306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 137662306a36Sopenharmony_ci i2s_tdm_runtime_suspend(&pdev->dev); 137762306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_cierr_disable_hclk: 138062306a36Sopenharmony_ci clk_disable_unprepare(i2s_tdm->hclk); 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci return ret; 138362306a36Sopenharmony_ci} 138462306a36Sopenharmony_ci 138562306a36Sopenharmony_cistatic int rockchip_i2s_tdm_remove(struct platform_device *pdev) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci if (!pm_runtime_status_suspended(&pdev->dev)) 138862306a36Sopenharmony_ci i2s_tdm_runtime_suspend(&pdev->dev); 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci return 0; 139362306a36Sopenharmony_ci} 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_cistatic int __maybe_unused rockchip_i2s_tdm_suspend(struct device *dev) 139662306a36Sopenharmony_ci{ 139762306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci regcache_mark_dirty(i2s_tdm->regmap); 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci return 0; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic int __maybe_unused rockchip_i2s_tdm_resume(struct device *dev) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); 140762306a36Sopenharmony_ci int ret; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci ret = pm_runtime_resume_and_get(dev); 141062306a36Sopenharmony_ci if (ret < 0) 141162306a36Sopenharmony_ci return ret; 141262306a36Sopenharmony_ci ret = regcache_sync(i2s_tdm->regmap); 141362306a36Sopenharmony_ci pm_runtime_put(dev); 141462306a36Sopenharmony_ci 141562306a36Sopenharmony_ci return ret; 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_cistatic const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = { 141962306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume, 142062306a36Sopenharmony_ci NULL) 142162306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend, 142262306a36Sopenharmony_ci rockchip_i2s_tdm_resume) 142362306a36Sopenharmony_ci}; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_cistatic struct platform_driver rockchip_i2s_tdm_driver = { 142662306a36Sopenharmony_ci .probe = rockchip_i2s_tdm_probe, 142762306a36Sopenharmony_ci .remove = rockchip_i2s_tdm_remove, 142862306a36Sopenharmony_ci .driver = { 142962306a36Sopenharmony_ci .name = DRV_NAME, 143062306a36Sopenharmony_ci .of_match_table = of_match_ptr(rockchip_i2s_tdm_match), 143162306a36Sopenharmony_ci .pm = &rockchip_i2s_tdm_pm_ops, 143262306a36Sopenharmony_ci }, 143362306a36Sopenharmony_ci}; 143462306a36Sopenharmony_cimodule_platform_driver(rockchip_i2s_tdm_driver); 143562306a36Sopenharmony_ci 143662306a36Sopenharmony_ciMODULE_DESCRIPTION("ROCKCHIP I2S/TDM ASoC Interface"); 143762306a36Sopenharmony_ciMODULE_AUTHOR("Sugar Zhang <sugar.zhang@rock-chips.com>"); 143862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 143962306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRV_NAME); 144062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rockchip_i2s_tdm_match); 1441