Path: blob/master/sound/soc/rockchip/rockchip_i2s_tdm.c
26427 views
// SPDX-License-Identifier: GPL-2.0-only1// ALSA SoC Audio Layer - Rockchip I2S/TDM Controller driver23// Copyright (c) 2018 Rockchip Electronics Co. Ltd.4// Author: Sugar Zhang <[email protected]>5// Author: Nicolas Frattaroli <[email protected]>67#include <linux/clk.h>8#include <linux/clk-provider.h>9#include <linux/delay.h>10#include <linux/mfd/syscon.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/pm_runtime.h>14#include <linux/regmap.h>15#include <linux/reset.h>16#include <linux/spinlock.h>17#include <sound/dmaengine_pcm.h>18#include <sound/pcm_params.h>1920#include "rockchip_i2s_tdm.h"2122#define DRV_NAME "rockchip-i2s-tdm"2324#define CH_GRP_MAX 4 /* The max channel 8 / 2 */25#define MULTIPLEX_CH_MAX 102627#define TRCM_TXRX 028#define TRCM_TX 129#define TRCM_RX 23031struct txrx_config {32u32 addr;33u32 reg;34u32 txonly;35u32 rxonly;36};3738struct rk_i2s_soc_data {39u32 softrst_offset;40u32 grf_reg_offset;41u32 grf_shift;42int config_count;43const struct txrx_config *configs;44int (*init)(struct device *dev, u32 addr);45};4647struct rk_i2s_tdm_dev {48struct device *dev;49struct clk *hclk;50struct clk *mclk_tx;51struct clk *mclk_rx;52struct regmap *regmap;53struct regmap *grf;54struct snd_dmaengine_dai_dma_data capture_dma_data;55struct snd_dmaengine_dai_dma_data playback_dma_data;56struct reset_control *tx_reset;57struct reset_control *rx_reset;58const struct rk_i2s_soc_data *soc_data;59bool is_master_mode;60bool io_multiplex;61bool tdm_mode;62unsigned int frame_width;63unsigned int clk_trcm;64unsigned int i2s_sdis[CH_GRP_MAX];65unsigned int i2s_sdos[CH_GRP_MAX];66int refcount;67spinlock_t lock; /* xfer lock */68bool has_playback;69bool has_capture;70struct snd_soc_dai_driver *dai;71unsigned int mclk_rx_freq;72unsigned int mclk_tx_freq;73};7475static int to_ch_num(unsigned int val)76{77switch (val) {78case I2S_CHN_4:79return 4;80case I2S_CHN_6:81return 6;82case I2S_CHN_8:83return 8;84default:85return 2;86}87}8889static void i2s_tdm_disable_unprepare_mclk(struct rk_i2s_tdm_dev *i2s_tdm)90{91clk_disable_unprepare(i2s_tdm->mclk_tx);92clk_disable_unprepare(i2s_tdm->mclk_rx);93}9495/**96* i2s_tdm_prepare_enable_mclk - prepare to enable all mclks, disable them on97* failure.98* @i2s_tdm: rk_i2s_tdm_dev struct99*100* This function attempts to enable all mclk clocks, but cleans up after101* itself on failure. Guarantees to balance its calls.102*103* Returns success (0) or negative errno.104*/105static int i2s_tdm_prepare_enable_mclk(struct rk_i2s_tdm_dev *i2s_tdm)106{107int ret = 0;108109ret = clk_prepare_enable(i2s_tdm->mclk_tx);110if (ret)111goto err_mclk_tx;112ret = clk_prepare_enable(i2s_tdm->mclk_rx);113if (ret)114goto err_mclk_rx;115116return 0;117118err_mclk_rx:119clk_disable_unprepare(i2s_tdm->mclk_tx);120err_mclk_tx:121return ret;122}123124static int i2s_tdm_runtime_suspend(struct device *dev)125{126struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);127128regcache_cache_only(i2s_tdm->regmap, true);129i2s_tdm_disable_unprepare_mclk(i2s_tdm);130131clk_disable_unprepare(i2s_tdm->hclk);132133return 0;134}135136static int i2s_tdm_runtime_resume(struct device *dev)137{138struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);139int ret;140141ret = clk_prepare_enable(i2s_tdm->hclk);142if (ret)143goto err_hclk;144145ret = i2s_tdm_prepare_enable_mclk(i2s_tdm);146if (ret)147goto err_mclk;148149regcache_cache_only(i2s_tdm->regmap, false);150regcache_mark_dirty(i2s_tdm->regmap);151152ret = regcache_sync(i2s_tdm->regmap);153if (ret)154goto err_regcache;155156return 0;157158err_regcache:159i2s_tdm_disable_unprepare_mclk(i2s_tdm);160err_mclk:161clk_disable_unprepare(i2s_tdm->hclk);162err_hclk:163return ret;164}165166static inline struct rk_i2s_tdm_dev *to_info(struct snd_soc_dai *dai)167{168return snd_soc_dai_get_drvdata(dai);169}170171/*172* Makes sure that both tx and rx are reset at the same time to sync lrck173* when clk_trcm > 0.174*/175static void rockchip_snd_xfer_sync_reset(struct rk_i2s_tdm_dev *i2s_tdm)176{177/* This is technically race-y.178*179* In an ideal world, we could atomically assert both resets at the180* same time, through an atomic bulk reset API. This API however does181* not exist, so what the downstream vendor code used to do was182* implement half a reset controller here and require the CRU to be183* passed to the driver as a device tree node. Violating abstractions184* like that is bad, especially when it influences something like the185* bindings which are supposed to describe the hardware, not whatever186* workarounds the driver needs, so it was dropped.187*188* In practice, asserting the resets one by one appears to work just189* fine for playback. During duplex (playback + capture) operation,190* this might become an issue, but that should be solved by the191* implementation of the aforementioned API, not by shoving a reset192* controller into an audio driver.193*/194195reset_control_assert(i2s_tdm->tx_reset);196reset_control_assert(i2s_tdm->rx_reset);197udelay(10);198reset_control_deassert(i2s_tdm->tx_reset);199reset_control_deassert(i2s_tdm->rx_reset);200udelay(10);201}202203static void rockchip_snd_reset(struct reset_control *rc)204{205reset_control_assert(rc);206udelay(10);207reset_control_deassert(rc);208udelay(10);209}210211static void rockchip_snd_xfer_clear(struct rk_i2s_tdm_dev *i2s_tdm,212unsigned int clr)213{214unsigned int xfer_mask = 0;215unsigned int xfer_val = 0;216unsigned int val;217int retry = 10;218bool tx = clr & I2S_CLR_TXC;219bool rx = clr & I2S_CLR_RXC;220221if (!(rx || tx))222return;223224if (tx) {225xfer_mask = I2S_XFER_TXS_START;226xfer_val = I2S_XFER_TXS_STOP;227}228if (rx) {229xfer_mask |= I2S_XFER_RXS_START;230xfer_val |= I2S_XFER_RXS_STOP;231}232233regmap_update_bits(i2s_tdm->regmap, I2S_XFER, xfer_mask, xfer_val);234udelay(150);235regmap_update_bits(i2s_tdm->regmap, I2S_CLR, clr, clr);236237regmap_read(i2s_tdm->regmap, I2S_CLR, &val);238/* Wait on the clear operation to finish */239while (val) {240udelay(15);241regmap_read(i2s_tdm->regmap, I2S_CLR, &val);242retry--;243if (!retry) {244dev_warn(i2s_tdm->dev, "clear failed, reset %s%s\n",245tx ? "tx" : "", rx ? "rx" : "");246if (rx && tx)247rockchip_snd_xfer_sync_reset(i2s_tdm);248else if (tx)249rockchip_snd_reset(i2s_tdm->tx_reset);250else if (rx)251rockchip_snd_reset(i2s_tdm->rx_reset);252break;253}254}255}256257static inline void rockchip_enable_tde(struct regmap *regmap)258{259regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE,260I2S_DMACR_TDE_ENABLE);261}262263static inline void rockchip_disable_tde(struct regmap *regmap)264{265regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_TDE_ENABLE,266I2S_DMACR_TDE_DISABLE);267}268269static inline void rockchip_enable_rde(struct regmap *regmap)270{271regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE,272I2S_DMACR_RDE_ENABLE);273}274275static inline void rockchip_disable_rde(struct regmap *regmap)276{277regmap_update_bits(regmap, I2S_DMACR, I2S_DMACR_RDE_ENABLE,278I2S_DMACR_RDE_DISABLE);279}280281/* only used when clk_trcm > 0 */282static void rockchip_snd_txrxctrl(struct snd_pcm_substream *substream,283struct snd_soc_dai *dai, int on)284{285struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);286unsigned long flags;287288spin_lock_irqsave(&i2s_tdm->lock, flags);289if (on) {290if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)291rockchip_enable_tde(i2s_tdm->regmap);292else293rockchip_enable_rde(i2s_tdm->regmap);294295if (++i2s_tdm->refcount == 1) {296rockchip_snd_xfer_sync_reset(i2s_tdm);297regmap_update_bits(i2s_tdm->regmap, I2S_XFER,298I2S_XFER_TXS_START |299I2S_XFER_RXS_START,300I2S_XFER_TXS_START |301I2S_XFER_RXS_START);302}303} else {304if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)305rockchip_disable_tde(i2s_tdm->regmap);306else307rockchip_disable_rde(i2s_tdm->regmap);308309if (--i2s_tdm->refcount == 0) {310rockchip_snd_xfer_clear(i2s_tdm,311I2S_CLR_TXC | I2S_CLR_RXC);312}313}314spin_unlock_irqrestore(&i2s_tdm->lock, flags);315}316317static void rockchip_snd_txctrl(struct rk_i2s_tdm_dev *i2s_tdm, int on)318{319if (on) {320rockchip_enable_tde(i2s_tdm->regmap);321322regmap_update_bits(i2s_tdm->regmap, I2S_XFER,323I2S_XFER_TXS_START,324I2S_XFER_TXS_START);325} else {326rockchip_disable_tde(i2s_tdm->regmap);327328rockchip_snd_xfer_clear(i2s_tdm, I2S_CLR_TXC);329}330}331332static void rockchip_snd_rxctrl(struct rk_i2s_tdm_dev *i2s_tdm, int on)333{334if (on) {335rockchip_enable_rde(i2s_tdm->regmap);336337regmap_update_bits(i2s_tdm->regmap, I2S_XFER,338I2S_XFER_RXS_START,339I2S_XFER_RXS_START);340} else {341rockchip_disable_rde(i2s_tdm->regmap);342343rockchip_snd_xfer_clear(i2s_tdm, I2S_CLR_RXC);344}345}346347static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai,348unsigned int fmt)349{350struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai);351unsigned int mask, val, tdm_val, txcr_val, rxcr_val;352int ret;353bool is_tdm = i2s_tdm->tdm_mode;354355ret = pm_runtime_resume_and_get(cpu_dai->dev);356if (ret < 0 && ret != -EACCES)357return ret;358359mask = I2S_CKR_MSS_MASK;360switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {361case SND_SOC_DAIFMT_BP_FP:362val = I2S_CKR_MSS_MASTER;363i2s_tdm->is_master_mode = true;364break;365case SND_SOC_DAIFMT_BC_FC:366val = I2S_CKR_MSS_SLAVE;367i2s_tdm->is_master_mode = false;368break;369default:370ret = -EINVAL;371goto err_pm_put;372}373374regmap_update_bits(i2s_tdm->regmap, I2S_CKR, mask, val);375376mask = I2S_CKR_CKP_MASK | I2S_CKR_TLP_MASK | I2S_CKR_RLP_MASK;377switch (fmt & SND_SOC_DAIFMT_INV_MASK) {378case SND_SOC_DAIFMT_NB_NF:379val = I2S_CKR_CKP_NORMAL |380I2S_CKR_TLP_NORMAL |381I2S_CKR_RLP_NORMAL;382break;383case SND_SOC_DAIFMT_NB_IF:384val = I2S_CKR_CKP_NORMAL |385I2S_CKR_TLP_INVERTED |386I2S_CKR_RLP_INVERTED;387break;388case SND_SOC_DAIFMT_IB_NF:389val = I2S_CKR_CKP_INVERTED |390I2S_CKR_TLP_NORMAL |391I2S_CKR_RLP_NORMAL;392break;393case SND_SOC_DAIFMT_IB_IF:394val = I2S_CKR_CKP_INVERTED |395I2S_CKR_TLP_INVERTED |396I2S_CKR_RLP_INVERTED;397break;398default:399ret = -EINVAL;400goto err_pm_put;401}402403regmap_update_bits(i2s_tdm->regmap, I2S_CKR, mask, val);404405switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {406case SND_SOC_DAIFMT_RIGHT_J:407txcr_val = I2S_TXCR_IBM_RSJM;408rxcr_val = I2S_RXCR_IBM_RSJM;409break;410case SND_SOC_DAIFMT_LEFT_J:411txcr_val = I2S_TXCR_IBM_LSJM;412rxcr_val = I2S_RXCR_IBM_LSJM;413break;414case SND_SOC_DAIFMT_I2S:415txcr_val = I2S_TXCR_IBM_NORMAL;416rxcr_val = I2S_RXCR_IBM_NORMAL;417break;418case SND_SOC_DAIFMT_DSP_A: /* PCM delay 1 mode */419txcr_val = I2S_TXCR_TFS_PCM | I2S_TXCR_PBM_MODE(1);420rxcr_val = I2S_RXCR_TFS_PCM | I2S_RXCR_PBM_MODE(1);421break;422case SND_SOC_DAIFMT_DSP_B: /* PCM no delay mode */423txcr_val = I2S_TXCR_TFS_PCM;424rxcr_val = I2S_RXCR_TFS_PCM;425break;426default:427ret = -EINVAL;428goto err_pm_put;429}430431mask = I2S_TXCR_IBM_MASK | I2S_TXCR_TFS_MASK | I2S_TXCR_PBM_MASK;432regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, txcr_val);433434mask = I2S_RXCR_IBM_MASK | I2S_RXCR_TFS_MASK | I2S_RXCR_PBM_MASK;435regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, rxcr_val);436437if (is_tdm) {438switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {439case SND_SOC_DAIFMT_RIGHT_J:440val = I2S_TXCR_TFS_TDM_I2S;441tdm_val = TDM_SHIFT_CTRL(2);442break;443case SND_SOC_DAIFMT_LEFT_J:444val = I2S_TXCR_TFS_TDM_I2S;445tdm_val = TDM_SHIFT_CTRL(1);446break;447case SND_SOC_DAIFMT_I2S:448val = I2S_TXCR_TFS_TDM_I2S;449tdm_val = TDM_SHIFT_CTRL(0);450break;451case SND_SOC_DAIFMT_DSP_A:452val = I2S_TXCR_TFS_TDM_PCM;453tdm_val = TDM_SHIFT_CTRL(2);454break;455case SND_SOC_DAIFMT_DSP_B:456val = I2S_TXCR_TFS_TDM_PCM;457tdm_val = TDM_SHIFT_CTRL(4);458break;459default:460ret = -EINVAL;461goto err_pm_put;462}463464tdm_val |= TDM_FSYNC_WIDTH_SEL1(1);465tdm_val |= TDM_FSYNC_WIDTH_HALF_FRAME;466467mask = I2S_TXCR_TFS_MASK;468regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val);469regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val);470471mask = TDM_FSYNC_WIDTH_SEL1_MSK | TDM_FSYNC_WIDTH_SEL0_MSK |472TDM_SHIFT_CTRL_MSK;473regmap_update_bits(i2s_tdm->regmap, I2S_TDM_TXCR,474mask, tdm_val);475regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR,476mask, tdm_val);477}478479err_pm_put:480pm_runtime_put(cpu_dai->dev);481482return ret;483}484485static void rockchip_i2s_tdm_xfer_pause(struct snd_pcm_substream *substream,486struct rk_i2s_tdm_dev *i2s_tdm)487{488int stream;489490stream = SNDRV_PCM_STREAM_LAST - substream->stream;491if (stream == SNDRV_PCM_STREAM_PLAYBACK)492rockchip_disable_tde(i2s_tdm->regmap);493else494rockchip_disable_rde(i2s_tdm->regmap);495496rockchip_snd_xfer_clear(i2s_tdm, I2S_CLR_TXC | I2S_CLR_RXC);497}498499static void rockchip_i2s_tdm_xfer_resume(struct snd_pcm_substream *substream,500struct rk_i2s_tdm_dev *i2s_tdm)501{502int stream;503504stream = SNDRV_PCM_STREAM_LAST - substream->stream;505if (stream == SNDRV_PCM_STREAM_PLAYBACK)506rockchip_enable_tde(i2s_tdm->regmap);507else508rockchip_enable_rde(i2s_tdm->regmap);509510regmap_update_bits(i2s_tdm->regmap, I2S_XFER,511I2S_XFER_TXS_START |512I2S_XFER_RXS_START,513I2S_XFER_TXS_START |514I2S_XFER_RXS_START);515}516517static int rockchip_i2s_io_multiplex(struct snd_pcm_substream *substream,518struct snd_soc_dai *dai)519{520struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);521int usable_chs = MULTIPLEX_CH_MAX;522unsigned int val = 0;523524if (!i2s_tdm->io_multiplex)525return 0;526527if (IS_ERR_OR_NULL(i2s_tdm->grf)) {528dev_err(i2s_tdm->dev,529"io multiplex not supported for this device\n");530return -EINVAL;531}532533if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {534struct snd_pcm_str *playback_str =535&substream->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK];536537if (playback_str->substream_opened) {538regmap_read(i2s_tdm->regmap, I2S_TXCR, &val);539val &= I2S_TXCR_CSR_MASK;540usable_chs = MULTIPLEX_CH_MAX - to_ch_num(val);541}542543regmap_read(i2s_tdm->regmap, I2S_RXCR, &val);544val &= I2S_RXCR_CSR_MASK;545546if (to_ch_num(val) > usable_chs) {547dev_err(i2s_tdm->dev,548"Capture channels (%d) > usable channels (%d)\n",549to_ch_num(val), usable_chs);550return -EINVAL;551}552553} else {554struct snd_pcm_str *capture_str =555&substream->pcm->streams[SNDRV_PCM_STREAM_CAPTURE];556557if (capture_str->substream_opened) {558regmap_read(i2s_tdm->regmap, I2S_RXCR, &val);559val &= I2S_RXCR_CSR_MASK;560usable_chs = MULTIPLEX_CH_MAX - to_ch_num(val);561}562563regmap_read(i2s_tdm->regmap, I2S_TXCR, &val);564val &= I2S_TXCR_CSR_MASK;565566if (to_ch_num(val) > usable_chs) {567dev_err(i2s_tdm->dev,568"Playback channels (%d) > usable channels (%d)\n",569to_ch_num(val), usable_chs);570return -EINVAL;571}572}573574val <<= i2s_tdm->soc_data->grf_shift;575val |= (I2S_IO_DIRECTION_MASK << i2s_tdm->soc_data->grf_shift) << 16;576regmap_write(i2s_tdm->grf, i2s_tdm->soc_data->grf_reg_offset, val);577578return 0;579}580581static int rockchip_i2s_trcm_mode(struct snd_pcm_substream *substream,582struct snd_soc_dai *dai,583unsigned int div_bclk,584unsigned int div_lrck,585unsigned int fmt)586{587struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);588unsigned long flags;589590if (!i2s_tdm->clk_trcm)591return 0;592593spin_lock_irqsave(&i2s_tdm->lock, flags);594if (i2s_tdm->refcount)595rockchip_i2s_tdm_xfer_pause(substream, i2s_tdm);596597regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV,598I2S_CLKDIV_TXM_MASK | I2S_CLKDIV_RXM_MASK,599I2S_CLKDIV_TXM(div_bclk) | I2S_CLKDIV_RXM(div_bclk));600regmap_update_bits(i2s_tdm->regmap, I2S_CKR,601I2S_CKR_TSD_MASK | I2S_CKR_RSD_MASK,602I2S_CKR_TSD(div_lrck) | I2S_CKR_RSD(div_lrck));603604if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)605regmap_update_bits(i2s_tdm->regmap, I2S_TXCR,606I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK,607fmt);608else609regmap_update_bits(i2s_tdm->regmap, I2S_RXCR,610I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK,611fmt);612613if (i2s_tdm->refcount)614rockchip_i2s_tdm_xfer_resume(substream, i2s_tdm);615spin_unlock_irqrestore(&i2s_tdm->lock, flags);616617return 0;618}619620static int rockchip_i2s_tdm_set_sysclk(struct snd_soc_dai *cpu_dai, int stream,621unsigned int freq, int dir)622{623struct rk_i2s_tdm_dev *i2s_tdm = to_info(cpu_dai);624625if (i2s_tdm->clk_trcm) {626i2s_tdm->mclk_tx_freq = freq;627i2s_tdm->mclk_rx_freq = freq;628} else {629if (stream == SNDRV_PCM_STREAM_PLAYBACK)630i2s_tdm->mclk_tx_freq = freq;631else632i2s_tdm->mclk_rx_freq = freq;633}634635dev_dbg(i2s_tdm->dev, "The target mclk_%s freq is: %d\n",636stream ? "rx" : "tx", freq);637638return 0;639}640641static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,642struct snd_pcm_hw_params *params,643struct snd_soc_dai *dai)644{645struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);646unsigned int val = 0;647unsigned int mclk_rate, bclk_rate, div_bclk = 4, div_lrck = 64;648int err;649650if (i2s_tdm->is_master_mode) {651struct clk *mclk;652653if (i2s_tdm->clk_trcm == TRCM_TX) {654mclk = i2s_tdm->mclk_tx;655mclk_rate = i2s_tdm->mclk_tx_freq;656} else if (i2s_tdm->clk_trcm == TRCM_RX) {657mclk = i2s_tdm->mclk_rx;658mclk_rate = i2s_tdm->mclk_rx_freq;659} else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {660mclk = i2s_tdm->mclk_tx;661mclk_rate = i2s_tdm->mclk_tx_freq;662} else {663mclk = i2s_tdm->mclk_rx;664mclk_rate = i2s_tdm->mclk_rx_freq;665}666667err = clk_set_rate(mclk, mclk_rate);668if (err)669return err;670671mclk_rate = clk_get_rate(mclk);672bclk_rate = i2s_tdm->frame_width * params_rate(params);673if (!bclk_rate)674return -EINVAL;675676div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);677div_lrck = bclk_rate / params_rate(params);678}679680switch (params_format(params)) {681case SNDRV_PCM_FORMAT_S8:682val |= I2S_TXCR_VDW(8);683break;684case SNDRV_PCM_FORMAT_S16_LE:685val |= I2S_TXCR_VDW(16);686break;687case SNDRV_PCM_FORMAT_S20_3LE:688val |= I2S_TXCR_VDW(20);689break;690case SNDRV_PCM_FORMAT_S24_LE:691val |= I2S_TXCR_VDW(24);692break;693case SNDRV_PCM_FORMAT_S32_LE:694val |= I2S_TXCR_VDW(32);695break;696default:697return -EINVAL;698}699700switch (params_channels(params)) {701case 8:702val |= I2S_CHN_8;703break;704case 6:705val |= I2S_CHN_6;706break;707case 4:708val |= I2S_CHN_4;709break;710case 2:711val |= I2S_CHN_2;712break;713default:714return -EINVAL;715}716717if (i2s_tdm->clk_trcm) {718rockchip_i2s_trcm_mode(substream, dai, div_bclk, div_lrck, val);719} else if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {720regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV,721I2S_CLKDIV_TXM_MASK,722I2S_CLKDIV_TXM(div_bclk));723regmap_update_bits(i2s_tdm->regmap, I2S_CKR,724I2S_CKR_TSD_MASK,725I2S_CKR_TSD(div_lrck));726regmap_update_bits(i2s_tdm->regmap, I2S_TXCR,727I2S_TXCR_VDW_MASK | I2S_TXCR_CSR_MASK,728val);729} else {730regmap_update_bits(i2s_tdm->regmap, I2S_CLKDIV,731I2S_CLKDIV_RXM_MASK,732I2S_CLKDIV_RXM(div_bclk));733regmap_update_bits(i2s_tdm->regmap, I2S_CKR,734I2S_CKR_RSD_MASK,735I2S_CKR_RSD(div_lrck));736regmap_update_bits(i2s_tdm->regmap, I2S_RXCR,737I2S_RXCR_VDW_MASK | I2S_RXCR_CSR_MASK,738val);739}740741return rockchip_i2s_io_multiplex(substream, dai);742}743744static int rockchip_i2s_tdm_trigger(struct snd_pcm_substream *substream,745int cmd, struct snd_soc_dai *dai)746{747struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai);748749switch (cmd) {750case SNDRV_PCM_TRIGGER_START:751case SNDRV_PCM_TRIGGER_RESUME:752case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:753if (i2s_tdm->clk_trcm)754rockchip_snd_txrxctrl(substream, dai, 1);755else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)756rockchip_snd_rxctrl(i2s_tdm, 1);757else758rockchip_snd_txctrl(i2s_tdm, 1);759break;760case SNDRV_PCM_TRIGGER_SUSPEND:761case SNDRV_PCM_TRIGGER_STOP:762case SNDRV_PCM_TRIGGER_PAUSE_PUSH:763if (i2s_tdm->clk_trcm)764rockchip_snd_txrxctrl(substream, dai, 0);765else if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)766rockchip_snd_rxctrl(i2s_tdm, 0);767else768rockchip_snd_txctrl(i2s_tdm, 0);769break;770default:771return -EINVAL;772}773774return 0;775}776777static int rockchip_i2s_tdm_dai_probe(struct snd_soc_dai *dai)778{779struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);780781if (i2s_tdm->has_capture)782snd_soc_dai_dma_data_set_capture(dai, &i2s_tdm->capture_dma_data);783if (i2s_tdm->has_playback)784snd_soc_dai_dma_data_set_playback(dai, &i2s_tdm->playback_dma_data);785786return 0;787}788789static int rockchip_dai_tdm_slot(struct snd_soc_dai *dai,790unsigned int tx_mask, unsigned int rx_mask,791int slots, int slot_width)792{793struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);794unsigned int mask, val;795796i2s_tdm->tdm_mode = true;797i2s_tdm->frame_width = slots * slot_width;798mask = TDM_SLOT_BIT_WIDTH_MSK | TDM_FRAME_WIDTH_MSK;799val = TDM_SLOT_BIT_WIDTH(slot_width) |800TDM_FRAME_WIDTH(slots * slot_width);801regmap_update_bits(i2s_tdm->regmap, I2S_TDM_TXCR,802mask, val);803regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR,804mask, val);805806return 0;807}808809static int rockchip_i2s_tdm_set_bclk_ratio(struct snd_soc_dai *dai,810unsigned int ratio)811{812struct rk_i2s_tdm_dev *i2s_tdm = snd_soc_dai_get_drvdata(dai);813814if (ratio < 32 || ratio > 512 || ratio % 2 == 1)815return -EINVAL;816817i2s_tdm->frame_width = ratio;818819return 0;820}821822static const struct snd_soc_dai_ops rockchip_i2s_tdm_dai_ops = {823.probe = rockchip_i2s_tdm_dai_probe,824.hw_params = rockchip_i2s_tdm_hw_params,825.set_bclk_ratio = rockchip_i2s_tdm_set_bclk_ratio,826.set_fmt = rockchip_i2s_tdm_set_fmt,827.set_sysclk = rockchip_i2s_tdm_set_sysclk,828.set_tdm_slot = rockchip_dai_tdm_slot,829.trigger = rockchip_i2s_tdm_trigger,830};831832static const struct snd_soc_component_driver rockchip_i2s_tdm_component = {833.name = DRV_NAME,834.legacy_dai_naming = 1,835};836837static bool rockchip_i2s_tdm_wr_reg(struct device *dev, unsigned int reg)838{839switch (reg) {840case I2S_TXCR:841case I2S_RXCR:842case I2S_CKR:843case I2S_DMACR:844case I2S_INTCR:845case I2S_XFER:846case I2S_CLR:847case I2S_TXDR:848case I2S_TDM_TXCR:849case I2S_TDM_RXCR:850case I2S_CLKDIV:851return true;852default:853return false;854}855}856857static bool rockchip_i2s_tdm_rd_reg(struct device *dev, unsigned int reg)858{859switch (reg) {860case I2S_TXCR:861case I2S_RXCR:862case I2S_CKR:863case I2S_DMACR:864case I2S_INTCR:865case I2S_XFER:866case I2S_CLR:867case I2S_TXDR:868case I2S_RXDR:869case I2S_TXFIFOLR:870case I2S_INTSR:871case I2S_RXFIFOLR:872case I2S_TDM_TXCR:873case I2S_TDM_RXCR:874case I2S_CLKDIV:875return true;876default:877return false;878}879}880881static bool rockchip_i2s_tdm_volatile_reg(struct device *dev, unsigned int reg)882{883switch (reg) {884case I2S_TXFIFOLR:885case I2S_INTSR:886case I2S_CLR:887case I2S_TXDR:888case I2S_RXDR:889case I2S_RXFIFOLR:890return true;891default:892return false;893}894}895896static bool rockchip_i2s_tdm_precious_reg(struct device *dev, unsigned int reg)897{898if (reg == I2S_RXDR)899return true;900return false;901}902903static const struct reg_default rockchip_i2s_tdm_reg_defaults[] = {904{0x00, 0x7200000f},905{0x04, 0x01c8000f},906{0x08, 0x00001f1f},907{0x10, 0x001f0000},908{0x14, 0x01f00000},909{0x30, 0x00003eff},910{0x34, 0x00003eff},911{0x38, 0x00000707},912};913914static const struct regmap_config rockchip_i2s_tdm_regmap_config = {915.reg_bits = 32,916.reg_stride = 4,917.val_bits = 32,918.max_register = I2S_CLKDIV,919.reg_defaults = rockchip_i2s_tdm_reg_defaults,920.num_reg_defaults = ARRAY_SIZE(rockchip_i2s_tdm_reg_defaults),921.writeable_reg = rockchip_i2s_tdm_wr_reg,922.readable_reg = rockchip_i2s_tdm_rd_reg,923.volatile_reg = rockchip_i2s_tdm_volatile_reg,924.precious_reg = rockchip_i2s_tdm_precious_reg,925.cache_type = REGCACHE_FLAT,926};927928static int common_soc_init(struct device *dev, u32 addr)929{930struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);931const struct txrx_config *configs = i2s_tdm->soc_data->configs;932u32 reg = 0, val = 0, trcm = i2s_tdm->clk_trcm;933int i;934935if (trcm == TRCM_TXRX)936return 0;937938if (IS_ERR_OR_NULL(i2s_tdm->grf)) {939dev_err(i2s_tdm->dev,940"no grf present but non-txrx TRCM specified\n");941return -EINVAL;942}943944for (i = 0; i < i2s_tdm->soc_data->config_count; i++) {945if (addr != configs[i].addr)946continue;947reg = configs[i].reg;948if (trcm == TRCM_TX)949val = configs[i].txonly;950else951val = configs[i].rxonly;952953if (reg)954regmap_write(i2s_tdm->grf, reg, val);955}956957return 0;958}959960static const struct txrx_config px30_txrx_config[] = {961{ 0xff060000, 0x184, PX30_I2S0_CLK_TXONLY, PX30_I2S0_CLK_RXONLY },962};963964static const struct txrx_config rk1808_txrx_config[] = {965{ 0xff7e0000, 0x190, RK1808_I2S0_CLK_TXONLY, RK1808_I2S0_CLK_RXONLY },966};967968static const struct txrx_config rk3308_txrx_config[] = {969{ 0xff300000, 0x308, RK3308_I2S0_CLK_TXONLY, RK3308_I2S0_CLK_RXONLY },970{ 0xff310000, 0x308, RK3308_I2S1_CLK_TXONLY, RK3308_I2S1_CLK_RXONLY },971};972973static const struct txrx_config rk3568_txrx_config[] = {974{ 0xfe410000, 0x504, RK3568_I2S1_CLK_TXONLY, RK3568_I2S1_CLK_RXONLY },975{ 0xfe410000, 0x508, RK3568_I2S1_MCLK_TX_OE, RK3568_I2S1_MCLK_RX_OE },976{ 0xfe420000, 0x508, RK3568_I2S2_MCLK_OE, RK3568_I2S2_MCLK_OE },977{ 0xfe430000, 0x504, RK3568_I2S3_CLK_TXONLY, RK3568_I2S3_CLK_RXONLY },978{ 0xfe430000, 0x508, RK3568_I2S3_MCLK_TXONLY, RK3568_I2S3_MCLK_RXONLY },979{ 0xfe430000, 0x508, RK3568_I2S3_MCLK_OE, RK3568_I2S3_MCLK_OE },980};981982static const struct txrx_config rv1126_txrx_config[] = {983{ 0xff800000, 0x10260, RV1126_I2S0_CLK_TXONLY, RV1126_I2S0_CLK_RXONLY },984};985986static const struct rk_i2s_soc_data px30_i2s_soc_data = {987.softrst_offset = 0x0300,988.configs = px30_txrx_config,989.config_count = ARRAY_SIZE(px30_txrx_config),990.init = common_soc_init,991};992993static const struct rk_i2s_soc_data rk1808_i2s_soc_data = {994.softrst_offset = 0x0300,995.configs = rk1808_txrx_config,996.config_count = ARRAY_SIZE(rk1808_txrx_config),997.init = common_soc_init,998};9991000static const struct rk_i2s_soc_data rk3308_i2s_soc_data = {1001.softrst_offset = 0x0400,1002.grf_reg_offset = 0x0308,1003.grf_shift = 5,1004.configs = rk3308_txrx_config,1005.config_count = ARRAY_SIZE(rk3308_txrx_config),1006.init = common_soc_init,1007};10081009static const struct rk_i2s_soc_data rk3568_i2s_soc_data = {1010.softrst_offset = 0x0400,1011.configs = rk3568_txrx_config,1012.config_count = ARRAY_SIZE(rk3568_txrx_config),1013.init = common_soc_init,1014};10151016static const struct rk_i2s_soc_data rv1126_i2s_soc_data = {1017.softrst_offset = 0x0300,1018.configs = rv1126_txrx_config,1019.config_count = ARRAY_SIZE(rv1126_txrx_config),1020.init = common_soc_init,1021};10221023static const struct of_device_id rockchip_i2s_tdm_match[] = {1024{ .compatible = "rockchip,px30-i2s-tdm", .data = &px30_i2s_soc_data },1025{ .compatible = "rockchip,rk1808-i2s-tdm", .data = &rk1808_i2s_soc_data },1026{ .compatible = "rockchip,rk3308-i2s-tdm", .data = &rk3308_i2s_soc_data },1027{ .compatible = "rockchip,rk3568-i2s-tdm", .data = &rk3568_i2s_soc_data },1028{ .compatible = "rockchip,rk3588-i2s-tdm" },1029{ .compatible = "rockchip,rv1126-i2s-tdm", .data = &rv1126_i2s_soc_data },1030{},1031};10321033static const struct snd_soc_dai_driver i2s_tdm_dai = {1034.ops = &rockchip_i2s_tdm_dai_ops,1035};10361037static int rockchip_i2s_tdm_init_dai(struct rk_i2s_tdm_dev *i2s_tdm)1038{1039struct snd_soc_dai_driver *dai;1040struct property *dma_names;1041const char *dma_name;1042u64 formats = (SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_S16_LE |1043SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S24_LE |1044SNDRV_PCM_FMTBIT_S32_LE);1045struct device_node *node = i2s_tdm->dev->of_node;10461047of_property_for_each_string(node, "dma-names", dma_names, dma_name) {1048if (!strcmp(dma_name, "tx"))1049i2s_tdm->has_playback = true;1050if (!strcmp(dma_name, "rx"))1051i2s_tdm->has_capture = true;1052}10531054dai = devm_kmemdup(i2s_tdm->dev, &i2s_tdm_dai,1055sizeof(*dai), GFP_KERNEL);1056if (!dai)1057return -ENOMEM;10581059if (i2s_tdm->has_playback) {1060dai->playback.stream_name = "Playback";1061dai->playback.channels_min = 2;1062dai->playback.channels_max = 8;1063dai->playback.rates = SNDRV_PCM_RATE_8000_192000;1064dai->playback.formats = formats;1065}10661067if (i2s_tdm->has_capture) {1068dai->capture.stream_name = "Capture";1069dai->capture.channels_min = 2;1070dai->capture.channels_max = 8;1071dai->capture.rates = SNDRV_PCM_RATE_8000_192000;1072dai->capture.formats = formats;1073}10741075if (i2s_tdm->clk_trcm != TRCM_TXRX)1076dai->symmetric_rate = 1;10771078i2s_tdm->dai = dai;10791080return 0;1081}10821083static int rockchip_i2s_tdm_path_check(struct rk_i2s_tdm_dev *i2s_tdm,1084int num,1085bool is_rx_path)1086{1087unsigned int *i2s_data;1088int i, j;10891090if (is_rx_path)1091i2s_data = i2s_tdm->i2s_sdis;1092else1093i2s_data = i2s_tdm->i2s_sdos;10941095for (i = 0; i < num; i++) {1096if (i2s_data[i] > CH_GRP_MAX - 1) {1097dev_err(i2s_tdm->dev,1098"%s path i2s_data[%d]: %d is too high, max is: %d\n",1099is_rx_path ? "RX" : "TX",1100i, i2s_data[i], CH_GRP_MAX);1101return -EINVAL;1102}11031104for (j = 0; j < num; j++) {1105if (i == j)1106continue;11071108if (i2s_data[i] == i2s_data[j]) {1109dev_err(i2s_tdm->dev,1110"%s path invalid routed i2s_data: [%d]%d == [%d]%d\n",1111is_rx_path ? "RX" : "TX",1112i, i2s_data[i],1113j, i2s_data[j]);1114return -EINVAL;1115}1116}1117}11181119return 0;1120}11211122static void rockchip_i2s_tdm_tx_path_config(struct rk_i2s_tdm_dev *i2s_tdm,1123int num)1124{1125int idx;11261127for (idx = 0; idx < num; idx++) {1128regmap_update_bits(i2s_tdm->regmap, I2S_TXCR,1129I2S_TXCR_PATH_MASK(idx),1130I2S_TXCR_PATH(idx, i2s_tdm->i2s_sdos[idx]));1131}1132}11331134static void rockchip_i2s_tdm_rx_path_config(struct rk_i2s_tdm_dev *i2s_tdm,1135int num)1136{1137int idx;11381139for (idx = 0; idx < num; idx++) {1140regmap_update_bits(i2s_tdm->regmap, I2S_RXCR,1141I2S_RXCR_PATH_MASK(idx),1142I2S_RXCR_PATH(idx, i2s_tdm->i2s_sdis[idx]));1143}1144}11451146static void rockchip_i2s_tdm_path_config(struct rk_i2s_tdm_dev *i2s_tdm,1147int num, bool is_rx_path)1148{1149if (is_rx_path)1150rockchip_i2s_tdm_rx_path_config(i2s_tdm, num);1151else1152rockchip_i2s_tdm_tx_path_config(i2s_tdm, num);1153}11541155static int rockchip_i2s_tdm_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm,1156struct device_node *np,1157bool is_rx_path)1158{1159char *i2s_tx_path_prop = "rockchip,i2s-tx-route";1160char *i2s_rx_path_prop = "rockchip,i2s-rx-route";1161char *i2s_path_prop;1162unsigned int *i2s_data;1163int num, ret = 0;11641165if (is_rx_path) {1166i2s_path_prop = i2s_rx_path_prop;1167i2s_data = i2s_tdm->i2s_sdis;1168} else {1169i2s_path_prop = i2s_tx_path_prop;1170i2s_data = i2s_tdm->i2s_sdos;1171}11721173num = of_count_phandle_with_args(np, i2s_path_prop, NULL);1174if (num < 0) {1175if (num != -ENOENT) {1176dev_err(i2s_tdm->dev,1177"Failed to read '%s' num: %d\n",1178i2s_path_prop, num);1179ret = num;1180}1181return ret;1182} else if (num != CH_GRP_MAX) {1183dev_err(i2s_tdm->dev,1184"The num: %d should be: %d\n", num, CH_GRP_MAX);1185return -EINVAL;1186}11871188ret = of_property_read_u32_array(np, i2s_path_prop,1189i2s_data, num);1190if (ret < 0) {1191dev_err(i2s_tdm->dev,1192"Failed to read '%s': %d\n",1193i2s_path_prop, ret);1194return ret;1195}11961197ret = rockchip_i2s_tdm_path_check(i2s_tdm, num, is_rx_path);1198if (ret < 0) {1199dev_err(i2s_tdm->dev,1200"Failed to check i2s data bus: %d\n", ret);1201return ret;1202}12031204rockchip_i2s_tdm_path_config(i2s_tdm, num, is_rx_path);12051206return 0;1207}12081209static int rockchip_i2s_tdm_tx_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm,1210struct device_node *np)1211{1212return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 0);1213}12141215static int rockchip_i2s_tdm_rx_path_prepare(struct rk_i2s_tdm_dev *i2s_tdm,1216struct device_node *np)1217{1218return rockchip_i2s_tdm_path_prepare(i2s_tdm, np, 1);1219}12201221static int rockchip_i2s_tdm_probe(struct platform_device *pdev)1222{1223struct device_node *node = pdev->dev.of_node;1224struct rk_i2s_tdm_dev *i2s_tdm;1225struct resource *res;1226void __iomem *regs;1227int ret;12281229i2s_tdm = devm_kzalloc(&pdev->dev, sizeof(*i2s_tdm), GFP_KERNEL);1230if (!i2s_tdm)1231return -ENOMEM;12321233i2s_tdm->dev = &pdev->dev;12341235spin_lock_init(&i2s_tdm->lock);1236i2s_tdm->soc_data = device_get_match_data(&pdev->dev);1237i2s_tdm->frame_width = 64;12381239i2s_tdm->clk_trcm = TRCM_TXRX;1240if (of_property_read_bool(node, "rockchip,trcm-sync-tx-only"))1241i2s_tdm->clk_trcm = TRCM_TX;1242if (of_property_read_bool(node, "rockchip,trcm-sync-rx-only")) {1243if (i2s_tdm->clk_trcm) {1244dev_err(i2s_tdm->dev, "invalid trcm-sync configuration\n");1245return -EINVAL;1246}1247i2s_tdm->clk_trcm = TRCM_RX;1248}12491250ret = rockchip_i2s_tdm_init_dai(i2s_tdm);1251if (ret)1252return ret;12531254i2s_tdm->grf = syscon_regmap_lookup_by_phandle(node, "rockchip,grf");1255i2s_tdm->tx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev,1256"tx-m");1257if (IS_ERR(i2s_tdm->tx_reset)) {1258ret = PTR_ERR(i2s_tdm->tx_reset);1259return dev_err_probe(i2s_tdm->dev, ret,1260"Error in tx-m reset control\n");1261}12621263i2s_tdm->rx_reset = devm_reset_control_get_optional_exclusive(&pdev->dev,1264"rx-m");1265if (IS_ERR(i2s_tdm->rx_reset)) {1266ret = PTR_ERR(i2s_tdm->rx_reset);1267return dev_err_probe(i2s_tdm->dev, ret,1268"Error in rx-m reset control\n");1269}12701271i2s_tdm->hclk = devm_clk_get(&pdev->dev, "hclk");1272if (IS_ERR(i2s_tdm->hclk)) {1273return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->hclk),1274"Failed to get clock hclk\n");1275}12761277i2s_tdm->mclk_tx = devm_clk_get(&pdev->dev, "mclk_tx");1278if (IS_ERR(i2s_tdm->mclk_tx)) {1279return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->mclk_tx),1280"Failed to get clock mclk_tx\n");1281}12821283i2s_tdm->mclk_rx = devm_clk_get(&pdev->dev, "mclk_rx");1284if (IS_ERR(i2s_tdm->mclk_rx)) {1285return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->mclk_rx),1286"Failed to get clock mclk_rx\n");1287}12881289i2s_tdm->io_multiplex =1290of_property_read_bool(node, "rockchip,io-multiplex");12911292regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);1293if (IS_ERR(regs)) {1294return dev_err_probe(i2s_tdm->dev, PTR_ERR(regs),1295"Failed to get resource IORESOURCE_MEM\n");1296}12971298i2s_tdm->regmap = devm_regmap_init_mmio(&pdev->dev, regs,1299&rockchip_i2s_tdm_regmap_config);1300if (IS_ERR(i2s_tdm->regmap)) {1301return dev_err_probe(i2s_tdm->dev, PTR_ERR(i2s_tdm->regmap),1302"Failed to initialise regmap\n");1303}13041305if (i2s_tdm->has_playback) {1306i2s_tdm->playback_dma_data.addr = res->start + I2S_TXDR;1307i2s_tdm->playback_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;1308i2s_tdm->playback_dma_data.maxburst = 8;1309}13101311if (i2s_tdm->has_capture) {1312i2s_tdm->capture_dma_data.addr = res->start + I2S_RXDR;1313i2s_tdm->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;1314i2s_tdm->capture_dma_data.maxburst = 8;1315}13161317ret = rockchip_i2s_tdm_tx_path_prepare(i2s_tdm, node);1318if (ret < 0) {1319dev_err(&pdev->dev, "I2S TX path prepare failed: %d\n", ret);1320return ret;1321}13221323ret = rockchip_i2s_tdm_rx_path_prepare(i2s_tdm, node);1324if (ret < 0) {1325dev_err(&pdev->dev, "I2S RX path prepare failed: %d\n", ret);1326return ret;1327}13281329dev_set_drvdata(&pdev->dev, i2s_tdm);13301331ret = clk_prepare_enable(i2s_tdm->hclk);1332if (ret) {1333return dev_err_probe(i2s_tdm->dev, ret,1334"Failed to enable clock hclk\n");1335}13361337ret = i2s_tdm_prepare_enable_mclk(i2s_tdm);1338if (ret) {1339ret = dev_err_probe(i2s_tdm->dev, ret,1340"Failed to enable one or more mclks\n");1341goto err_disable_hclk;1342}13431344pm_runtime_enable(&pdev->dev);13451346regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_TDL_MASK,1347I2S_DMACR_TDL(16));1348regmap_update_bits(i2s_tdm->regmap, I2S_DMACR, I2S_DMACR_RDL_MASK,1349I2S_DMACR_RDL(16));1350regmap_update_bits(i2s_tdm->regmap, I2S_CKR, I2S_CKR_TRCM_MASK,1351i2s_tdm->clk_trcm << I2S_CKR_TRCM_SHIFT);13521353if (i2s_tdm->soc_data && i2s_tdm->soc_data->init)1354i2s_tdm->soc_data->init(&pdev->dev, res->start);13551356ret = devm_snd_soc_register_component(&pdev->dev,1357&rockchip_i2s_tdm_component,1358i2s_tdm->dai, 1);13591360if (ret) {1361dev_err(&pdev->dev, "Could not register DAI\n");1362goto err_suspend;1363}13641365ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);1366if (ret) {1367dev_err(&pdev->dev, "Could not register PCM\n");1368goto err_suspend;1369}13701371return 0;13721373err_suspend:1374if (!pm_runtime_status_suspended(&pdev->dev))1375i2s_tdm_runtime_suspend(&pdev->dev);1376pm_runtime_disable(&pdev->dev);13771378err_disable_hclk:1379clk_disable_unprepare(i2s_tdm->hclk);13801381return ret;1382}13831384static void rockchip_i2s_tdm_remove(struct platform_device *pdev)1385{1386if (!pm_runtime_status_suspended(&pdev->dev))1387i2s_tdm_runtime_suspend(&pdev->dev);13881389pm_runtime_disable(&pdev->dev);1390}13911392static int rockchip_i2s_tdm_suspend(struct device *dev)1393{1394struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);13951396regcache_mark_dirty(i2s_tdm->regmap);13971398return 0;1399}14001401static int rockchip_i2s_tdm_resume(struct device *dev)1402{1403struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev);1404int ret;14051406ret = pm_runtime_resume_and_get(dev);1407if (ret < 0)1408return ret;1409ret = regcache_sync(i2s_tdm->regmap);1410pm_runtime_put(dev);14111412return ret;1413}14141415static const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = {1416RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume, NULL)1417SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend, rockchip_i2s_tdm_resume)1418};14191420static struct platform_driver rockchip_i2s_tdm_driver = {1421.probe = rockchip_i2s_tdm_probe,1422.remove = rockchip_i2s_tdm_remove,1423.driver = {1424.name = DRV_NAME,1425.of_match_table = rockchip_i2s_tdm_match,1426.pm = pm_ptr(&rockchip_i2s_tdm_pm_ops),1427},1428};1429module_platform_driver(rockchip_i2s_tdm_driver);14301431MODULE_DESCRIPTION("ROCKCHIP I2S/TDM ASoC Interface");1432MODULE_AUTHOR("Sugar Zhang <[email protected]>");1433MODULE_LICENSE("GPL v2");1434MODULE_ALIAS("platform:" DRV_NAME);1435MODULE_DEVICE_TABLE(of, rockchip_i2s_tdm_match);143614371438