1165a30e4SFabio Estevam // SPDX-License-Identifier: GPL-2.0
2165a30e4SFabio Estevam //
3165a30e4SFabio Estevam // Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver
4165a30e4SFabio Estevam //
5165a30e4SFabio Estevam // Copyright (C) 2013 Freescale Semiconductor, Inc.
6165a30e4SFabio Estevam //
7165a30e4SFabio Estevam // Based on stmp3xxx_spdif_dai.c
8165a30e4SFabio Estevam // Vladimir Barinov <vbarinov@embeddedalley.com>
9165a30e4SFabio Estevam // Copyright 2008 SigmaTel, Inc
10165a30e4SFabio Estevam // Copyright 2008 Embedded Alley Solutions, Inc
11a2388a49SNicolin Chen
12add180edSXiubo Li #include <linux/bitrev.h>
13a2388a49SNicolin Chen #include <linux/clk.h>
14add180edSXiubo Li #include <linux/module.h>
15a2388a49SNicolin Chen #include <linux/of_address.h>
16a2388a49SNicolin Chen #include <linux/of_device.h>
17a2388a49SNicolin Chen #include <linux/of_irq.h>
18add180edSXiubo Li #include <linux/regmap.h>
199cb2b379SShengjiu Wang #include <linux/pm_runtime.h>
20a2388a49SNicolin Chen
21a2388a49SNicolin Chen #include <sound/asoundef.h>
22a2388a49SNicolin Chen #include <sound/dmaengine_pcm.h>
23add180edSXiubo Li #include <sound/soc.h>
24a2388a49SNicolin Chen
25a2388a49SNicolin Chen #include "fsl_spdif.h"
2634dcdebeSShengjiu Wang #include "fsl_utils.h"
27a2388a49SNicolin Chen #include "imx-pcm.h"
28a2388a49SNicolin Chen
29a2388a49SNicolin Chen #define FSL_SPDIF_TXFIFO_WML 0x8
30a2388a49SNicolin Chen #define FSL_SPDIF_RXFIFO_WML 0x8
31a2388a49SNicolin Chen
32a2388a49SNicolin Chen #define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC)
33f3a30baaSNicolin Chen #define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL |\
34f3a30baaSNicolin Chen INT_URX_OV | INT_QRX_FUL | INT_QRX_OV |\
35f3a30baaSNicolin Chen INT_UQ_SYNC | INT_UQ_ERR | INT_RXFIFO_RESYNC |\
36f3a30baaSNicolin Chen INT_LOSS_LOCK | INT_DPLL_LOCKED)
37f3a30baaSNicolin Chen
38f3a30baaSNicolin Chen #define SIE_INTR_FOR(tx) (tx ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE)
39a2388a49SNicolin Chen
40a2388a49SNicolin Chen /* Index list for the values that has if (DPLL Locked) condition */
41a2388a49SNicolin Chen static u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb };
42a2388a49SNicolin Chen #define SRPC_NODPLL_START1 0x5
43a2388a49SNicolin Chen #define SRPC_NODPLL_START2 0xc
44a2388a49SNicolin Chen
45a2388a49SNicolin Chen #define DEFAULT_RXCLK_SRC 1
46a2388a49SNicolin Chen
47e31a4a93SRobert Rosengren #define RX_SAMPLE_RATE_KCONTROL "RX Sample Rate"
48e31a4a93SRobert Rosengren
49f61b9273SShengjiu Wang /**
50f61b9273SShengjiu Wang * struct fsl_spdif_soc_data: soc specific data
51f61b9273SShengjiu Wang *
52f61b9273SShengjiu Wang * @imx: for imx platform
53f61b9273SShengjiu Wang * @shared_root_clock: flag of sharing a clock source with others;
54f61b9273SShengjiu Wang * so the driver shouldn't set root clock rate
55604e5178SViorel Suman * @raw_capture_mode: if raw capture mode support
56638cec39SShengjiu Wang * @cchannel_192b: if there are registers for 192bits C channel data
57516232e3SShengjiu Wang * @interrupts: interrupt number
58516232e3SShengjiu Wang * @tx_burst: tx maxburst size
59516232e3SShengjiu Wang * @rx_burst: rx maxburst size
60516232e3SShengjiu Wang * @tx_formats: tx supported data format
61f61b9273SShengjiu Wang */
62f61b9273SShengjiu Wang struct fsl_spdif_soc_data {
63f61b9273SShengjiu Wang bool imx;
64f61b9273SShengjiu Wang bool shared_root_clock;
65604e5178SViorel Suman bool raw_capture_mode;
66638cec39SShengjiu Wang bool cchannel_192b;
67516232e3SShengjiu Wang u32 interrupts;
68516232e3SShengjiu Wang u32 tx_burst;
69516232e3SShengjiu Wang u32 rx_burst;
70516232e3SShengjiu Wang u64 tx_formats;
71f61b9273SShengjiu Wang };
72f61b9273SShengjiu Wang
73a2388a49SNicolin Chen /*
74a2388a49SNicolin Chen * SPDIF control structure
75a2388a49SNicolin Chen * Defines channel status, subcode and Q sub
76a2388a49SNicolin Chen */
77a2388a49SNicolin Chen struct spdif_mixer_control {
78a2388a49SNicolin Chen /* spinlock to access control data */
79a2388a49SNicolin Chen spinlock_t ctl_lock;
80a2388a49SNicolin Chen
81a2388a49SNicolin Chen /* IEC958 channel tx status bit */
82a2388a49SNicolin Chen unsigned char ch_status[4];
83a2388a49SNicolin Chen
84a2388a49SNicolin Chen /* User bits */
85a2388a49SNicolin Chen unsigned char subcode[2 * SPDIF_UBITS_SIZE];
86a2388a49SNicolin Chen
87a2388a49SNicolin Chen /* Q subcode part of user bits */
88a2388a49SNicolin Chen unsigned char qsub[2 * SPDIF_QSUB_SIZE];
89a2388a49SNicolin Chen
90a2388a49SNicolin Chen /* Buffer offset for U/Q */
91a2388a49SNicolin Chen u32 upos;
92a2388a49SNicolin Chen u32 qpos;
93a2388a49SNicolin Chen
94a2388a49SNicolin Chen /* Ready buffer index of the two buffers */
95a2388a49SNicolin Chen u32 ready_buf;
96a2388a49SNicolin Chen };
97a2388a49SNicolin Chen
98b8a832a0SNicolin Chen /**
9928fd6ff1SPierre-Louis Bossart * struct fsl_spdif_priv - Freescale SPDIF private data
10028fd6ff1SPierre-Louis Bossart * @soc: SPDIF soc data
101b8a832a0SNicolin Chen * @fsl_spdif_control: SPDIF control data
102b8a832a0SNicolin Chen * @cpu_dai_drv: cpu dai driver
103e31a4a93SRobert Rosengren * @snd_card: sound card pointer
104e31a4a93SRobert Rosengren * @rxrate_kcontrol: kcontrol for RX Sample Rate
105b8a832a0SNicolin Chen * @pdev: platform device pointer
106b8a832a0SNicolin Chen * @regmap: regmap handler
107b8a832a0SNicolin Chen * @dpll_locked: dpll lock flag
108b8a832a0SNicolin Chen * @txrate: the best rates for playback
109b8a832a0SNicolin Chen * @txclk_df: STC_TXCLK_DF dividers value for playback
110b8a832a0SNicolin Chen * @sysclk_df: STC_SYSCLK_DF dividers value for playback
111b8a832a0SNicolin Chen * @txclk_src: STC_TXCLK_SRC values for playback
112b8a832a0SNicolin Chen * @rxclk_src: SRPC_CLKSRC_SEL values for capture
113b8a832a0SNicolin Chen * @txclk: tx clock sources for playback
114b8a832a0SNicolin Chen * @rxclk: rx clock sources for capture
115b8a832a0SNicolin Chen * @coreclk: core clock for register access via DMA
116b8a832a0SNicolin Chen * @sysclk: system clock for rx clock rate measurement
1170bc5680aSShengjiu Wang * @spbaclk: SPBA clock (optional, depending on SoC design)
118b8a832a0SNicolin Chen * @dma_params_tx: DMA parameters for transmit channel
119b8a832a0SNicolin Chen * @dma_params_rx: DMA parameters for receive channel
12028fd6ff1SPierre-Louis Bossart * @regcache_srpc: regcache for SRPC
12183bea088SViorel Suman * @bypass: status of bypass input to output
12234dcdebeSShengjiu Wang * @pll8k_clk: PLL clock for the rate of multiply of 8kHz
12334dcdebeSShengjiu Wang * @pll11k_clk: PLL clock for the rate of multiply of 11kHz
124b8a832a0SNicolin Chen */
125a2388a49SNicolin Chen struct fsl_spdif_priv {
126f61b9273SShengjiu Wang const struct fsl_spdif_soc_data *soc;
127a2388a49SNicolin Chen struct spdif_mixer_control fsl_spdif_control;
128a2388a49SNicolin Chen struct snd_soc_dai_driver cpu_dai_drv;
129e31a4a93SRobert Rosengren struct snd_card *snd_card;
130e31a4a93SRobert Rosengren struct snd_kcontrol *rxrate_kcontrol;
131a2388a49SNicolin Chen struct platform_device *pdev;
132a2388a49SNicolin Chen struct regmap *regmap;
133a2388a49SNicolin Chen bool dpll_locked;
134c7dfeed1SAnssi Hannula u32 txrate[SPDIF_TXRATE_MAX];
135e41a4a79SNicolin Chen u8 txclk_df[SPDIF_TXRATE_MAX];
1362231609aSViorel Suman u16 sysclk_df[SPDIF_TXRATE_MAX];
137a2388a49SNicolin Chen u8 txclk_src[SPDIF_TXRATE_MAX];
138a2388a49SNicolin Chen u8 rxclk_src;
1395bd998afSViorel Suman struct clk *txclk[STC_TXCLK_SRC_MAX];
140a2388a49SNicolin Chen struct clk *rxclk;
14108f7336eSNicolin Chen struct clk *coreclk;
1420b864390SNicolin Chen struct clk *sysclk;
1430bc5680aSShengjiu Wang struct clk *spbaclk;
144a2388a49SNicolin Chen struct snd_dmaengine_dai_dma_data dma_params_tx;
145a2388a49SNicolin Chen struct snd_dmaengine_dai_dma_data dma_params_rx;
146f9f4fa61SZidan Wang /* regcache for SRPC */
147f9f4fa61SZidan Wang u32 regcache_srpc;
14883bea088SViorel Suman bool bypass;
14934dcdebeSShengjiu Wang struct clk *pll8k_clk;
15034dcdebeSShengjiu Wang struct clk *pll11k_clk;
151a2388a49SNicolin Chen };
152a2388a49SNicolin Chen
153f61b9273SShengjiu Wang static struct fsl_spdif_soc_data fsl_spdif_vf610 = {
154f61b9273SShengjiu Wang .imx = false,
155f61b9273SShengjiu Wang .shared_root_clock = false,
156604e5178SViorel Suman .raw_capture_mode = false,
157516232e3SShengjiu Wang .interrupts = 1,
158516232e3SShengjiu Wang .tx_burst = FSL_SPDIF_TXFIFO_WML,
159516232e3SShengjiu Wang .rx_burst = FSL_SPDIF_RXFIFO_WML,
160516232e3SShengjiu Wang .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
161f61b9273SShengjiu Wang };
162f61b9273SShengjiu Wang
163f61b9273SShengjiu Wang static struct fsl_spdif_soc_data fsl_spdif_imx35 = {
164f61b9273SShengjiu Wang .imx = true,
165f61b9273SShengjiu Wang .shared_root_clock = false,
166604e5178SViorel Suman .raw_capture_mode = false,
167516232e3SShengjiu Wang .interrupts = 1,
168516232e3SShengjiu Wang .tx_burst = FSL_SPDIF_TXFIFO_WML,
169516232e3SShengjiu Wang .rx_burst = FSL_SPDIF_RXFIFO_WML,
170516232e3SShengjiu Wang .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
171f61b9273SShengjiu Wang };
172f61b9273SShengjiu Wang
173f61b9273SShengjiu Wang static struct fsl_spdif_soc_data fsl_spdif_imx6sx = {
174f61b9273SShengjiu Wang .imx = true,
175f61b9273SShengjiu Wang .shared_root_clock = true,
176604e5178SViorel Suman .raw_capture_mode = false,
177516232e3SShengjiu Wang .interrupts = 1,
178516232e3SShengjiu Wang .tx_burst = FSL_SPDIF_TXFIFO_WML,
179516232e3SShengjiu Wang .rx_burst = FSL_SPDIF_RXFIFO_WML,
180516232e3SShengjiu Wang .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
181516232e3SShengjiu Wang
182516232e3SShengjiu Wang };
183516232e3SShengjiu Wang
184516232e3SShengjiu Wang static struct fsl_spdif_soc_data fsl_spdif_imx8qm = {
185516232e3SShengjiu Wang .imx = true,
186516232e3SShengjiu Wang .shared_root_clock = true,
187604e5178SViorel Suman .raw_capture_mode = false,
188516232e3SShengjiu Wang .interrupts = 2,
189516232e3SShengjiu Wang .tx_burst = 2, /* Applied for EDMA */
190516232e3SShengjiu Wang .rx_burst = 2, /* Applied for EDMA */
191516232e3SShengjiu Wang .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */
192f61b9273SShengjiu Wang };
193f61b9273SShengjiu Wang
194604e5178SViorel Suman static struct fsl_spdif_soc_data fsl_spdif_imx8mm = {
195604e5178SViorel Suman .imx = true,
196604e5178SViorel Suman .shared_root_clock = false,
197604e5178SViorel Suman .raw_capture_mode = true,
198604e5178SViorel Suman .interrupts = 1,
199604e5178SViorel Suman .tx_burst = FSL_SPDIF_TXFIFO_WML,
200604e5178SViorel Suman .rx_burst = FSL_SPDIF_RXFIFO_WML,
201604e5178SViorel Suman .tx_formats = FSL_SPDIF_FORMATS_PLAYBACK,
202604e5178SViorel Suman };
203604e5178SViorel Suman
204a635d66bSShengjiu Wang static struct fsl_spdif_soc_data fsl_spdif_imx8ulp = {
205a635d66bSShengjiu Wang .imx = true,
206a635d66bSShengjiu Wang .shared_root_clock = true,
207a635d66bSShengjiu Wang .raw_capture_mode = false,
208a635d66bSShengjiu Wang .interrupts = 1,
209a635d66bSShengjiu Wang .tx_burst = 2, /* Applied for EDMA */
210a635d66bSShengjiu Wang .rx_burst = 2, /* Applied for EDMA */
211a635d66bSShengjiu Wang .tx_formats = SNDRV_PCM_FMTBIT_S24_LE, /* Applied for EDMA */
212638cec39SShengjiu Wang .cchannel_192b = true,
213a635d66bSShengjiu Wang };
214a635d66bSShengjiu Wang
215f61b9273SShengjiu Wang /* Check if clk is a root clock that does not share clock source with others */
fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv * spdif,int clk)216f61b9273SShengjiu Wang static inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk)
217f61b9273SShengjiu Wang {
218f61b9273SShengjiu Wang return (clk == STC_TXCLK_SPDIF_ROOT) && !spdif->soc->shared_root_clock;
219f61b9273SShengjiu Wang }
220f61b9273SShengjiu Wang
221a2388a49SNicolin Chen /* DPLL locked and lock loss interrupt handler */
spdif_irq_dpll_lock(struct fsl_spdif_priv * spdif_priv)222a2388a49SNicolin Chen static void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv)
223a2388a49SNicolin Chen {
224a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
225a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
226a2388a49SNicolin Chen u32 locked;
227a2388a49SNicolin Chen
228a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRPC, &locked);
229a2388a49SNicolin Chen locked &= SRPC_DPLL_LOCKED;
230a2388a49SNicolin Chen
231a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Rx dpll %s \n",
232a2388a49SNicolin Chen locked ? "locked" : "loss lock");
233a2388a49SNicolin Chen
234a2388a49SNicolin Chen spdif_priv->dpll_locked = locked ? true : false;
235e31a4a93SRobert Rosengren
236e31a4a93SRobert Rosengren if (spdif_priv->snd_card && spdif_priv->rxrate_kcontrol) {
237e31a4a93SRobert Rosengren snd_ctl_notify(spdif_priv->snd_card,
238e31a4a93SRobert Rosengren SNDRV_CTL_EVENT_MASK_VALUE,
239e31a4a93SRobert Rosengren &spdif_priv->rxrate_kcontrol->id);
240e31a4a93SRobert Rosengren }
241a2388a49SNicolin Chen }
242a2388a49SNicolin Chen
243a2388a49SNicolin Chen /* Receiver found illegal symbol interrupt handler */
spdif_irq_sym_error(struct fsl_spdif_priv * spdif_priv)244a2388a49SNicolin Chen static void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv)
245a2388a49SNicolin Chen {
246a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
247a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
248a2388a49SNicolin Chen
249a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n");
250a2388a49SNicolin Chen
251f3a30baaSNicolin Chen /* Clear illegal symbol if DPLL unlocked since no audio stream */
252f3a30baaSNicolin Chen if (!spdif_priv->dpll_locked)
253a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0);
254a2388a49SNicolin Chen }
255a2388a49SNicolin Chen
256a2388a49SNicolin Chen /* U/Q Channel receive register full */
spdif_irq_uqrx_full(struct fsl_spdif_priv * spdif_priv,char name)257a2388a49SNicolin Chen static void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name)
258a2388a49SNicolin Chen {
259a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
260a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
261a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
262a2388a49SNicolin Chen u32 *pos, size, val, reg;
263a2388a49SNicolin Chen
264a2388a49SNicolin Chen switch (name) {
265a2388a49SNicolin Chen case 'U':
266a2388a49SNicolin Chen pos = &ctrl->upos;
267a2388a49SNicolin Chen size = SPDIF_UBITS_SIZE;
268a2388a49SNicolin Chen reg = REG_SPDIF_SRU;
269a2388a49SNicolin Chen break;
270a2388a49SNicolin Chen case 'Q':
271a2388a49SNicolin Chen pos = &ctrl->qpos;
272a2388a49SNicolin Chen size = SPDIF_QSUB_SIZE;
273a2388a49SNicolin Chen reg = REG_SPDIF_SRQ;
274a2388a49SNicolin Chen break;
275a2388a49SNicolin Chen default:
276a2388a49SNicolin Chen dev_err(&pdev->dev, "unsupported channel name\n");
277a2388a49SNicolin Chen return;
278a2388a49SNicolin Chen }
279a2388a49SNicolin Chen
280a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name);
281a2388a49SNicolin Chen
282a2388a49SNicolin Chen if (*pos >= size * 2) {
283a2388a49SNicolin Chen *pos = 0;
284a2388a49SNicolin Chen } else if (unlikely((*pos % size) + 3 > size)) {
285d93c5066SColin Ian King dev_err(&pdev->dev, "User bit receive buffer overflow\n");
286a2388a49SNicolin Chen return;
287a2388a49SNicolin Chen }
288a2388a49SNicolin Chen
289a2388a49SNicolin Chen regmap_read(regmap, reg, &val);
290a2388a49SNicolin Chen ctrl->subcode[*pos++] = val >> 16;
291a2388a49SNicolin Chen ctrl->subcode[*pos++] = val >> 8;
292a2388a49SNicolin Chen ctrl->subcode[*pos++] = val;
293a2388a49SNicolin Chen }
294a2388a49SNicolin Chen
295a2388a49SNicolin Chen /* U/Q Channel sync found */
spdif_irq_uq_sync(struct fsl_spdif_priv * spdif_priv)296a2388a49SNicolin Chen static void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv)
297a2388a49SNicolin Chen {
298a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
299a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
300a2388a49SNicolin Chen
301a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n");
302a2388a49SNicolin Chen
303a2388a49SNicolin Chen /* U/Q buffer reset */
304a2388a49SNicolin Chen if (ctrl->qpos == 0)
305a2388a49SNicolin Chen return;
306a2388a49SNicolin Chen
307a2388a49SNicolin Chen /* Set ready to this buffer */
308a2388a49SNicolin Chen ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1;
309a2388a49SNicolin Chen }
310a2388a49SNicolin Chen
311a2388a49SNicolin Chen /* U/Q Channel framing error */
spdif_irq_uq_err(struct fsl_spdif_priv * spdif_priv)312a2388a49SNicolin Chen static void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv)
313a2388a49SNicolin Chen {
314a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
315a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
316a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
317a2388a49SNicolin Chen u32 val;
318a2388a49SNicolin Chen
319a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n");
320a2388a49SNicolin Chen
321a2388a49SNicolin Chen /* Read U/Q data to clear the irq and do buffer reset */
322a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRU, &val);
323a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRQ, &val);
324a2388a49SNicolin Chen
325a2388a49SNicolin Chen /* Drop this U/Q buffer */
326a2388a49SNicolin Chen ctrl->ready_buf = 0;
327a2388a49SNicolin Chen ctrl->upos = 0;
328a2388a49SNicolin Chen ctrl->qpos = 0;
329a2388a49SNicolin Chen }
330a2388a49SNicolin Chen
331a2388a49SNicolin Chen /* Get spdif interrupt status and clear the interrupt */
spdif_intr_status_clear(struct fsl_spdif_priv * spdif_priv)332a2388a49SNicolin Chen static u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv)
333a2388a49SNicolin Chen {
334a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
335a2388a49SNicolin Chen u32 val, val2;
336a2388a49SNicolin Chen
337a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SIS, &val);
338a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SIE, &val2);
339a2388a49SNicolin Chen
340a2388a49SNicolin Chen regmap_write(regmap, REG_SPDIF_SIC, val & val2);
341a2388a49SNicolin Chen
342a2388a49SNicolin Chen return val;
343a2388a49SNicolin Chen }
344a2388a49SNicolin Chen
spdif_isr(int irq,void * devid)345a2388a49SNicolin Chen static irqreturn_t spdif_isr(int irq, void *devid)
346a2388a49SNicolin Chen {
347a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid;
348a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
349a2388a49SNicolin Chen u32 sis;
350a2388a49SNicolin Chen
351a2388a49SNicolin Chen sis = spdif_intr_status_clear(spdif_priv);
352a2388a49SNicolin Chen
353a2388a49SNicolin Chen if (sis & INT_DPLL_LOCKED)
354a2388a49SNicolin Chen spdif_irq_dpll_lock(spdif_priv);
355a2388a49SNicolin Chen
356a2388a49SNicolin Chen if (sis & INT_TXFIFO_UNOV)
357a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n");
358a2388a49SNicolin Chen
359a2388a49SNicolin Chen if (sis & INT_TXFIFO_RESYNC)
360a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n");
361a2388a49SNicolin Chen
362a2388a49SNicolin Chen if (sis & INT_CNEW)
363a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: cstatus new\n");
364a2388a49SNicolin Chen
365a2388a49SNicolin Chen if (sis & INT_VAL_NOGOOD)
366a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: validity flag no good\n");
367a2388a49SNicolin Chen
368a2388a49SNicolin Chen if (sis & INT_SYM_ERR)
369a2388a49SNicolin Chen spdif_irq_sym_error(spdif_priv);
370a2388a49SNicolin Chen
371a2388a49SNicolin Chen if (sis & INT_BIT_ERR)
372a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n");
373a2388a49SNicolin Chen
374a2388a49SNicolin Chen if (sis & INT_URX_FUL)
375a2388a49SNicolin Chen spdif_irq_uqrx_full(spdif_priv, 'U');
376a2388a49SNicolin Chen
377a2388a49SNicolin Chen if (sis & INT_URX_OV)
378a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n");
379a2388a49SNicolin Chen
380a2388a49SNicolin Chen if (sis & INT_QRX_FUL)
381a2388a49SNicolin Chen spdif_irq_uqrx_full(spdif_priv, 'Q');
382a2388a49SNicolin Chen
383a2388a49SNicolin Chen if (sis & INT_QRX_OV)
384a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n");
385a2388a49SNicolin Chen
386a2388a49SNicolin Chen if (sis & INT_UQ_SYNC)
387a2388a49SNicolin Chen spdif_irq_uq_sync(spdif_priv);
388a2388a49SNicolin Chen
389a2388a49SNicolin Chen if (sis & INT_UQ_ERR)
390a2388a49SNicolin Chen spdif_irq_uq_err(spdif_priv);
391a2388a49SNicolin Chen
392a2388a49SNicolin Chen if (sis & INT_RXFIFO_UNOV)
393a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n");
394a2388a49SNicolin Chen
395a2388a49SNicolin Chen if (sis & INT_RXFIFO_RESYNC)
396a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n");
397a2388a49SNicolin Chen
398a2388a49SNicolin Chen if (sis & INT_LOSS_LOCK)
399a2388a49SNicolin Chen spdif_irq_dpll_lock(spdif_priv);
400a2388a49SNicolin Chen
401a2388a49SNicolin Chen /* FIXME: Write Tx FIFO to clear TxEm */
402a2388a49SNicolin Chen if (sis & INT_TX_EM)
403a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n");
404a2388a49SNicolin Chen
405a2388a49SNicolin Chen /* FIXME: Read Rx FIFO to clear RxFIFOFul */
406a2388a49SNicolin Chen if (sis & INT_RXFIFO_FUL)
407a2388a49SNicolin Chen dev_dbg(&pdev->dev, "isr: Rx FIFO full\n");
408a2388a49SNicolin Chen
409a2388a49SNicolin Chen return IRQ_HANDLED;
410a2388a49SNicolin Chen }
411a2388a49SNicolin Chen
spdif_softreset(struct fsl_spdif_priv * spdif_priv)412a2388a49SNicolin Chen static int spdif_softreset(struct fsl_spdif_priv *spdif_priv)
413a2388a49SNicolin Chen {
414a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
415a2388a49SNicolin Chen u32 val, cycle = 1000;
416a2388a49SNicolin Chen
417f9f4fa61SZidan Wang regcache_cache_bypass(regmap, true);
418f9f4fa61SZidan Wang
419a2388a49SNicolin Chen regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET);
420a2388a49SNicolin Chen
421a2388a49SNicolin Chen /*
422a2388a49SNicolin Chen * RESET bit would be cleared after finishing its reset procedure,
423a2388a49SNicolin Chen * which typically lasts 8 cycles. 1000 cycles will keep it safe.
424a2388a49SNicolin Chen */
425a2388a49SNicolin Chen do {
426a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SCR, &val);
427a2388a49SNicolin Chen } while ((val & SCR_SOFT_RESET) && cycle--);
428a2388a49SNicolin Chen
429f9f4fa61SZidan Wang regcache_cache_bypass(regmap, false);
430f9f4fa61SZidan Wang regcache_mark_dirty(regmap);
431f9f4fa61SZidan Wang regcache_sync(regmap);
432f9f4fa61SZidan Wang
433a2388a49SNicolin Chen if (cycle)
434a2388a49SNicolin Chen return 0;
435a2388a49SNicolin Chen else
436a2388a49SNicolin Chen return -EBUSY;
437a2388a49SNicolin Chen }
438a2388a49SNicolin Chen
spdif_set_cstatus(struct spdif_mixer_control * ctrl,u8 mask,u8 cstatus)439a2388a49SNicolin Chen static void spdif_set_cstatus(struct spdif_mixer_control *ctrl,
440a2388a49SNicolin Chen u8 mask, u8 cstatus)
441a2388a49SNicolin Chen {
442a2388a49SNicolin Chen ctrl->ch_status[3] &= ~mask;
443a2388a49SNicolin Chen ctrl->ch_status[3] |= cstatus & mask;
444a2388a49SNicolin Chen }
445a2388a49SNicolin Chen
spdif_write_channel_status(struct fsl_spdif_priv * spdif_priv)446a2388a49SNicolin Chen static void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv)
447a2388a49SNicolin Chen {
448a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
449a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
450a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
451a2388a49SNicolin Chen u32 ch_status;
452a2388a49SNicolin Chen
453a2388a49SNicolin Chen ch_status = (bitrev8(ctrl->ch_status[0]) << 16) |
454a2388a49SNicolin Chen (bitrev8(ctrl->ch_status[1]) << 8) |
455a2388a49SNicolin Chen bitrev8(ctrl->ch_status[2]);
456a2388a49SNicolin Chen regmap_write(regmap, REG_SPDIF_STCSCH, ch_status);
457a2388a49SNicolin Chen
458a2388a49SNicolin Chen dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status);
459a2388a49SNicolin Chen
460a2388a49SNicolin Chen ch_status = bitrev8(ctrl->ch_status[3]) << 16;
461a2388a49SNicolin Chen regmap_write(regmap, REG_SPDIF_STCSCL, ch_status);
462a2388a49SNicolin Chen
463a2388a49SNicolin Chen dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status);
464638cec39SShengjiu Wang
465638cec39SShengjiu Wang if (spdif_priv->soc->cchannel_192b) {
466638cec39SShengjiu Wang ch_status = (bitrev8(ctrl->ch_status[0]) << 24) |
467638cec39SShengjiu Wang (bitrev8(ctrl->ch_status[1]) << 16) |
468638cec39SShengjiu Wang (bitrev8(ctrl->ch_status[2]) << 8) |
469638cec39SShengjiu Wang bitrev8(ctrl->ch_status[3]);
470638cec39SShengjiu Wang
471638cec39SShengjiu Wang regmap_update_bits(regmap, REG_SPDIF_SCR, 0x1000000, 0x1000000);
472638cec39SShengjiu Wang
473638cec39SShengjiu Wang /*
474638cec39SShengjiu Wang * The first 32bit should be in REG_SPDIF_STCCA_31_0 register,
475638cec39SShengjiu Wang * but here we need to set REG_SPDIF_STCCA_191_160 on 8ULP
476638cec39SShengjiu Wang * then can get correct result with HDMI analyzer capture.
477638cec39SShengjiu Wang * There is a hardware bug here.
478638cec39SShengjiu Wang */
479638cec39SShengjiu Wang regmap_write(regmap, REG_SPDIF_STCCA_191_160, ch_status);
480638cec39SShengjiu Wang }
481a2388a49SNicolin Chen }
482a2388a49SNicolin Chen
483a2388a49SNicolin Chen /* Set SPDIF PhaseConfig register for rx clock */
spdif_set_rx_clksrc(struct fsl_spdif_priv * spdif_priv,enum spdif_gainsel gainsel,int dpll_locked)484a2388a49SNicolin Chen static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv,
485a2388a49SNicolin Chen enum spdif_gainsel gainsel, int dpll_locked)
486a2388a49SNicolin Chen {
487a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
488a2388a49SNicolin Chen u8 clksrc = spdif_priv->rxclk_src;
489a2388a49SNicolin Chen
490a2388a49SNicolin Chen if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX)
491a2388a49SNicolin Chen return -EINVAL;
492a2388a49SNicolin Chen
493a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SRPC,
494a2388a49SNicolin Chen SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
495a2388a49SNicolin Chen SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel));
496a2388a49SNicolin Chen
497a2388a49SNicolin Chen return 0;
498a2388a49SNicolin Chen }
499a2388a49SNicolin Chen
50034dcdebeSShengjiu Wang static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index);
50134dcdebeSShengjiu Wang
spdif_set_sample_rate(struct snd_pcm_substream * substream,int sample_rate)502a2388a49SNicolin Chen static int spdif_set_sample_rate(struct snd_pcm_substream *substream,
503a2388a49SNicolin Chen int sample_rate)
504a2388a49SNicolin Chen {
5059f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
50617198ae7SKuninori Morimoto struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
507a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
508a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
509a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
510a2388a49SNicolin Chen unsigned long csfs = 0;
511a2388a49SNicolin Chen u32 stc, mask, rate;
5122231609aSViorel Suman u16 sysclk_df;
5132231609aSViorel Suman u8 clk, txclk_df;
514a2388a49SNicolin Chen int ret;
515a2388a49SNicolin Chen
516a2388a49SNicolin Chen switch (sample_rate) {
51765bc25b8SMatus Gajdos case 22050:
51865bc25b8SMatus Gajdos rate = SPDIF_TXRATE_22050;
51965bc25b8SMatus Gajdos csfs = IEC958_AES3_CON_FS_22050;
52065bc25b8SMatus Gajdos break;
521a2388a49SNicolin Chen case 32000:
522a2388a49SNicolin Chen rate = SPDIF_TXRATE_32000;
523a2388a49SNicolin Chen csfs = IEC958_AES3_CON_FS_32000;
524a2388a49SNicolin Chen break;
525a2388a49SNicolin Chen case 44100:
526a2388a49SNicolin Chen rate = SPDIF_TXRATE_44100;
527a2388a49SNicolin Chen csfs = IEC958_AES3_CON_FS_44100;
528a2388a49SNicolin Chen break;
529a2388a49SNicolin Chen case 48000:
530a2388a49SNicolin Chen rate = SPDIF_TXRATE_48000;
531a2388a49SNicolin Chen csfs = IEC958_AES3_CON_FS_48000;
532a2388a49SNicolin Chen break;
5331bfa3eaaSShengjiu Wang case 88200:
5341bfa3eaaSShengjiu Wang rate = SPDIF_TXRATE_88200;
5351bfa3eaaSShengjiu Wang csfs = IEC958_AES3_CON_FS_88200;
5361bfa3eaaSShengjiu Wang break;
537c7dfeed1SAnssi Hannula case 96000:
538c7dfeed1SAnssi Hannula rate = SPDIF_TXRATE_96000;
539c7dfeed1SAnssi Hannula csfs = IEC958_AES3_CON_FS_96000;
540c7dfeed1SAnssi Hannula break;
5411bfa3eaaSShengjiu Wang case 176400:
5421bfa3eaaSShengjiu Wang rate = SPDIF_TXRATE_176400;
5431bfa3eaaSShengjiu Wang csfs = IEC958_AES3_CON_FS_176400;
5441bfa3eaaSShengjiu Wang break;
545c7dfeed1SAnssi Hannula case 192000:
546c7dfeed1SAnssi Hannula rate = SPDIF_TXRATE_192000;
547c7dfeed1SAnssi Hannula csfs = IEC958_AES3_CON_FS_192000;
548c7dfeed1SAnssi Hannula break;
549a2388a49SNicolin Chen default:
550a2388a49SNicolin Chen dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate);
551a2388a49SNicolin Chen return -EINVAL;
552a2388a49SNicolin Chen }
553a2388a49SNicolin Chen
55434dcdebeSShengjiu Wang ret = fsl_spdif_probe_txclk(spdif_priv, rate);
55534dcdebeSShengjiu Wang if (ret)
55634dcdebeSShengjiu Wang return ret;
55734dcdebeSShengjiu Wang
558a2388a49SNicolin Chen clk = spdif_priv->txclk_src[rate];
559a2388a49SNicolin Chen if (clk >= STC_TXCLK_SRC_MAX) {
560a2388a49SNicolin Chen dev_err(&pdev->dev, "tx clock source is out of range\n");
561a2388a49SNicolin Chen return -EINVAL;
562a2388a49SNicolin Chen }
563a2388a49SNicolin Chen
564e41a4a79SNicolin Chen txclk_df = spdif_priv->txclk_df[rate];
565e41a4a79SNicolin Chen if (txclk_df == 0) {
566e41a4a79SNicolin Chen dev_err(&pdev->dev, "the txclk_df can't be zero\n");
567a2388a49SNicolin Chen return -EINVAL;
568a2388a49SNicolin Chen }
569a2388a49SNicolin Chen
57027c647bfSNicolin Chen sysclk_df = spdif_priv->sysclk_df[rate];
57127c647bfSNicolin Chen
572f61b9273SShengjiu Wang if (!fsl_spdif_can_set_clk_rate(spdif_priv, clk))
5739c6344b3SNicolin Chen goto clk_set_bypass;
5749c6344b3SNicolin Chen
575f490f326SNicolin Chen /* The S/PDIF block needs a clock of 64 * fs * txclk_df */
5765bd998afSViorel Suman ret = clk_set_rate(spdif_priv->txclk[clk],
577f490f326SNicolin Chen 64 * sample_rate * txclk_df);
578a2388a49SNicolin Chen if (ret) {
579a2388a49SNicolin Chen dev_err(&pdev->dev, "failed to set tx clock rate\n");
580a2388a49SNicolin Chen return ret;
581a2388a49SNicolin Chen }
582a2388a49SNicolin Chen
5839c6344b3SNicolin Chen clk_set_bypass:
584a2388a49SNicolin Chen dev_dbg(&pdev->dev, "expected clock rate = %d\n",
58527c647bfSNicolin Chen (64 * sample_rate * txclk_df * sysclk_df));
586a2388a49SNicolin Chen dev_dbg(&pdev->dev, "actual clock rate = %ld\n",
5875bd998afSViorel Suman clk_get_rate(spdif_priv->txclk[clk]));
588a2388a49SNicolin Chen
589a2388a49SNicolin Chen /* set fs field in consumer channel status */
590a2388a49SNicolin Chen spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs);
591a2388a49SNicolin Chen
592a2388a49SNicolin Chen /* select clock source and divisor */
593f3a30baaSNicolin Chen stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) |
594f3a30baaSNicolin Chen STC_TXCLK_DF(txclk_df) | STC_SYSCLK_DF(sysclk_df);
595f3a30baaSNicolin Chen mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK |
596f3a30baaSNicolin Chen STC_TXCLK_DF_MASK | STC_SYSCLK_DF_MASK;
597a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc);
598a2388a49SNicolin Chen
599527cda78SNicolin Chen dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n",
600527cda78SNicolin Chen spdif_priv->txrate[rate], sample_rate);
601a2388a49SNicolin Chen
602a2388a49SNicolin Chen return 0;
603a2388a49SNicolin Chen }
604a2388a49SNicolin Chen
fsl_spdif_startup(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)6056b4c80f9SMark Brown static int fsl_spdif_startup(struct snd_pcm_substream *substream,
606a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai)
607a2388a49SNicolin Chen {
6089f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
60917198ae7SKuninori Morimoto struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
610a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
611a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
61289e0e250SDan Carpenter u32 scr, mask;
613a2388a49SNicolin Chen int ret;
614a2388a49SNicolin Chen
615a2388a49SNicolin Chen /* Reset module and interrupts only for first initialization */
6161d9fb19dSKuninori Morimoto if (!snd_soc_dai_active(cpu_dai)) {
617a2388a49SNicolin Chen ret = spdif_softreset(spdif_priv);
618a2388a49SNicolin Chen if (ret) {
619a2388a49SNicolin Chen dev_err(&pdev->dev, "failed to soft reset\n");
6209cb2b379SShengjiu Wang return ret;
621a2388a49SNicolin Chen }
622a2388a49SNicolin Chen
623a2388a49SNicolin Chen /* Disable all the interrupts */
624a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0);
625a2388a49SNicolin Chen }
626a2388a49SNicolin Chen
627a2388a49SNicolin Chen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
628a2388a49SNicolin Chen scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL |
629a2388a49SNicolin Chen SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP |
630a2388a49SNicolin Chen SCR_TXFIFO_FSEL_IF8;
631a2388a49SNicolin Chen mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
632a2388a49SNicolin Chen SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
633a2388a49SNicolin Chen SCR_TXFIFO_FSEL_MASK;
634a2388a49SNicolin Chen } else {
635a2388a49SNicolin Chen scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC;
636a2388a49SNicolin Chen mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
637a2388a49SNicolin Chen SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
638a2388a49SNicolin Chen }
639a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
640a2388a49SNicolin Chen
641a2388a49SNicolin Chen /* Power up SPDIF module */
642a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0);
643a2388a49SNicolin Chen
644a2388a49SNicolin Chen return 0;
645a2388a49SNicolin Chen }
646a2388a49SNicolin Chen
fsl_spdif_shutdown(struct snd_pcm_substream * substream,struct snd_soc_dai * cpu_dai)647a2388a49SNicolin Chen static void fsl_spdif_shutdown(struct snd_pcm_substream *substream,
648a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai)
649a2388a49SNicolin Chen {
6509f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
65117198ae7SKuninori Morimoto struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
652a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
6539cb2b379SShengjiu Wang u32 scr, mask;
654a2388a49SNicolin Chen
655a2388a49SNicolin Chen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
656a2388a49SNicolin Chen scr = 0;
657a2388a49SNicolin Chen mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK |
658a2388a49SNicolin Chen SCR_TXSEL_MASK | SCR_USRC_SEL_MASK |
659a2388a49SNicolin Chen SCR_TXFIFO_FSEL_MASK;
6606ddf6112SShengjiu Wang /* Disable TX clock */
6616ddf6112SShengjiu Wang regmap_update_bits(regmap, REG_SPDIF_STC, STC_TXCLK_ALL_EN_MASK, 0);
662a2388a49SNicolin Chen } else {
663a2388a49SNicolin Chen scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO;
664a2388a49SNicolin Chen mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK|
665a2388a49SNicolin Chen SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK;
666a2388a49SNicolin Chen }
667a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
668a2388a49SNicolin Chen
669a2388a49SNicolin Chen /* Power down SPDIF module only if tx&rx are both inactive */
6701d9fb19dSKuninori Morimoto if (!snd_soc_dai_active(cpu_dai)) {
671a2388a49SNicolin Chen spdif_intr_status_clear(spdif_priv);
672a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SCR,
673a2388a49SNicolin Chen SCR_LOW_POWER, SCR_LOW_POWER);
674a2388a49SNicolin Chen }
675a2388a49SNicolin Chen }
676a2388a49SNicolin Chen
spdif_reparent_rootclk(struct fsl_spdif_priv * spdif_priv,unsigned int sample_rate)67734dcdebeSShengjiu Wang static int spdif_reparent_rootclk(struct fsl_spdif_priv *spdif_priv, unsigned int sample_rate)
67834dcdebeSShengjiu Wang {
67934dcdebeSShengjiu Wang struct platform_device *pdev = spdif_priv->pdev;
68034dcdebeSShengjiu Wang struct clk *clk;
68134dcdebeSShengjiu Wang int ret;
68234dcdebeSShengjiu Wang
68334dcdebeSShengjiu Wang /* Reparent clock if required condition is true */
68434dcdebeSShengjiu Wang if (!fsl_spdif_can_set_clk_rate(spdif_priv, STC_TXCLK_SPDIF_ROOT))
68534dcdebeSShengjiu Wang return 0;
68634dcdebeSShengjiu Wang
68734dcdebeSShengjiu Wang /* Get root clock */
68834dcdebeSShengjiu Wang clk = spdif_priv->txclk[STC_TXCLK_SPDIF_ROOT];
68934dcdebeSShengjiu Wang
69034dcdebeSShengjiu Wang /* Disable clock first, for it was enabled by pm_runtime */
69134dcdebeSShengjiu Wang clk_disable_unprepare(clk);
69234dcdebeSShengjiu Wang fsl_asoc_reparent_pll_clocks(&pdev->dev, clk, spdif_priv->pll8k_clk,
69334dcdebeSShengjiu Wang spdif_priv->pll11k_clk, sample_rate);
69434dcdebeSShengjiu Wang ret = clk_prepare_enable(clk);
69534dcdebeSShengjiu Wang if (ret)
69634dcdebeSShengjiu Wang return ret;
69734dcdebeSShengjiu Wang
69834dcdebeSShengjiu Wang return 0;
69934dcdebeSShengjiu Wang }
fsl_spdif_hw_params(struct snd_pcm_substream * substream,struct snd_pcm_hw_params * params,struct snd_soc_dai * dai)700a2388a49SNicolin Chen static int fsl_spdif_hw_params(struct snd_pcm_substream *substream,
701a2388a49SNicolin Chen struct snd_pcm_hw_params *params,
702a2388a49SNicolin Chen struct snd_soc_dai *dai)
703a2388a49SNicolin Chen {
7049f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
70517198ae7SKuninori Morimoto struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
706a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
707a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
708a2388a49SNicolin Chen u32 sample_rate = params_rate(params);
709a2388a49SNicolin Chen int ret = 0;
710a2388a49SNicolin Chen
711a2388a49SNicolin Chen if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
71234dcdebeSShengjiu Wang ret = spdif_reparent_rootclk(spdif_priv, sample_rate);
71334dcdebeSShengjiu Wang if (ret) {
71434dcdebeSShengjiu Wang dev_err(&pdev->dev, "%s: reparent root clk failed: %d\n",
71534dcdebeSShengjiu Wang __func__, sample_rate);
71634dcdebeSShengjiu Wang return ret;
71734dcdebeSShengjiu Wang }
71834dcdebeSShengjiu Wang
719a2388a49SNicolin Chen ret = spdif_set_sample_rate(substream, sample_rate);
720a2388a49SNicolin Chen if (ret) {
721a2388a49SNicolin Chen dev_err(&pdev->dev, "%s: set sample rate failed: %d\n",
722a2388a49SNicolin Chen __func__, sample_rate);
723a2388a49SNicolin Chen return ret;
724a2388a49SNicolin Chen }
725a2388a49SNicolin Chen spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK,
726a2388a49SNicolin Chen IEC958_AES3_CON_CLOCK_1000PPM);
727a2388a49SNicolin Chen spdif_write_channel_status(spdif_priv);
728a2388a49SNicolin Chen } else {
729a2388a49SNicolin Chen /* Setup rx clock source */
730a2388a49SNicolin Chen ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1);
731a2388a49SNicolin Chen }
732a2388a49SNicolin Chen
733a2388a49SNicolin Chen return ret;
734a2388a49SNicolin Chen }
735a2388a49SNicolin Chen
fsl_spdif_trigger(struct snd_pcm_substream * substream,int cmd,struct snd_soc_dai * dai)736a2388a49SNicolin Chen static int fsl_spdif_trigger(struct snd_pcm_substream *substream,
737a2388a49SNicolin Chen int cmd, struct snd_soc_dai *dai)
738a2388a49SNicolin Chen {
7399f5f078aSKuninori Morimoto struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream);
74017198ae7SKuninori Morimoto struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0));
741a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
742f3a30baaSNicolin Chen bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
743f3a30baaSNicolin Chen u32 intr = SIE_INTR_FOR(tx);
744f3a30baaSNicolin Chen u32 dmaen = SCR_DMA_xX_EN(tx);
745a2388a49SNicolin Chen
746a2388a49SNicolin Chen switch (cmd) {
747a2388a49SNicolin Chen case SNDRV_PCM_TRIGGER_START:
748a2388a49SNicolin Chen case SNDRV_PCM_TRIGGER_RESUME:
749a2388a49SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
750a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr);
751a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen);
752a2388a49SNicolin Chen break;
753a2388a49SNicolin Chen case SNDRV_PCM_TRIGGER_STOP:
754a2388a49SNicolin Chen case SNDRV_PCM_TRIGGER_SUSPEND:
755a2388a49SNicolin Chen case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
756a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0);
757a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0);
7580e4c2b6bSMatus Gajdos regmap_write(regmap, REG_SPDIF_STL, 0x0);
7590e4c2b6bSMatus Gajdos regmap_write(regmap, REG_SPDIF_STR, 0x0);
760a2388a49SNicolin Chen break;
761a2388a49SNicolin Chen default:
762a2388a49SNicolin Chen return -EINVAL;
763a2388a49SNicolin Chen }
764a2388a49SNicolin Chen
765a2388a49SNicolin Chen return 0;
766a2388a49SNicolin Chen }
767a2388a49SNicolin Chen
768a2388a49SNicolin Chen /*
769a2388a49SNicolin Chen * FSL SPDIF IEC958 controller(mixer) functions
770a2388a49SNicolin Chen *
771a2388a49SNicolin Chen * Channel status get/put control
772a2388a49SNicolin Chen * User bit value get/put control
773a2388a49SNicolin Chen * Valid bit value get control
774a2388a49SNicolin Chen * DPLL lock status get control
775a2388a49SNicolin Chen * User bit sync mode selection control
776a2388a49SNicolin Chen */
777a2388a49SNicolin Chen
fsl_spdif_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)778a2388a49SNicolin Chen static int fsl_spdif_info(struct snd_kcontrol *kcontrol,
779a2388a49SNicolin Chen struct snd_ctl_elem_info *uinfo)
780a2388a49SNicolin Chen {
781a2388a49SNicolin Chen uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958;
782a2388a49SNicolin Chen uinfo->count = 1;
783a2388a49SNicolin Chen
784a2388a49SNicolin Chen return 0;
785a2388a49SNicolin Chen }
786a2388a49SNicolin Chen
fsl_spdif_pb_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uvalue)787a2388a49SNicolin Chen static int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol,
788a2388a49SNicolin Chen struct snd_ctl_elem_value *uvalue)
789a2388a49SNicolin Chen {
790a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
791a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
792a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
793a2388a49SNicolin Chen
794a2388a49SNicolin Chen uvalue->value.iec958.status[0] = ctrl->ch_status[0];
795a2388a49SNicolin Chen uvalue->value.iec958.status[1] = ctrl->ch_status[1];
796a2388a49SNicolin Chen uvalue->value.iec958.status[2] = ctrl->ch_status[2];
797a2388a49SNicolin Chen uvalue->value.iec958.status[3] = ctrl->ch_status[3];
798a2388a49SNicolin Chen
799a2388a49SNicolin Chen return 0;
800a2388a49SNicolin Chen }
801a2388a49SNicolin Chen
fsl_spdif_pb_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uvalue)802a2388a49SNicolin Chen static int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol,
803a2388a49SNicolin Chen struct snd_ctl_elem_value *uvalue)
804a2388a49SNicolin Chen {
805a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
806a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
807a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
808a2388a49SNicolin Chen
809a2388a49SNicolin Chen ctrl->ch_status[0] = uvalue->value.iec958.status[0];
810a2388a49SNicolin Chen ctrl->ch_status[1] = uvalue->value.iec958.status[1];
811a2388a49SNicolin Chen ctrl->ch_status[2] = uvalue->value.iec958.status[2];
812a2388a49SNicolin Chen ctrl->ch_status[3] = uvalue->value.iec958.status[3];
813a2388a49SNicolin Chen
814a2388a49SNicolin Chen spdif_write_channel_status(spdif_priv);
815a2388a49SNicolin Chen
816a2388a49SNicolin Chen return 0;
817a2388a49SNicolin Chen }
818a2388a49SNicolin Chen
819a2388a49SNicolin Chen /* Get channel status from SPDIF_RX_CCHAN register */
fsl_spdif_capture_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)820a2388a49SNicolin Chen static int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol,
821a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
822a2388a49SNicolin Chen {
823a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
824a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
825a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
826a2388a49SNicolin Chen u32 cstatus, val;
827a2388a49SNicolin Chen
828a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SIS, &val);
829f3a30baaSNicolin Chen if (!(val & INT_CNEW))
830a2388a49SNicolin Chen return -EAGAIN;
831a2388a49SNicolin Chen
832a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus);
833a2388a49SNicolin Chen ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF;
834a2388a49SNicolin Chen ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF;
835a2388a49SNicolin Chen ucontrol->value.iec958.status[2] = cstatus & 0xFF;
836a2388a49SNicolin Chen
837a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus);
838a2388a49SNicolin Chen ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF;
839a2388a49SNicolin Chen ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF;
840a2388a49SNicolin Chen ucontrol->value.iec958.status[5] = cstatus & 0xFF;
841a2388a49SNicolin Chen
842a2388a49SNicolin Chen /* Clear intr */
843a2388a49SNicolin Chen regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW);
844a2388a49SNicolin Chen
845a2388a49SNicolin Chen return 0;
846a2388a49SNicolin Chen }
847a2388a49SNicolin Chen
848a2388a49SNicolin Chen /*
849a2388a49SNicolin Chen * Get User bits (subcode) from chip value which readed out
850a2388a49SNicolin Chen * in UChannel register.
851a2388a49SNicolin Chen */
fsl_spdif_subcode_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)852a2388a49SNicolin Chen static int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol,
853a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
854a2388a49SNicolin Chen {
855a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
856a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
857a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
858a2388a49SNicolin Chen unsigned long flags;
859f3a30baaSNicolin Chen int ret = -EAGAIN;
860a2388a49SNicolin Chen
861a2388a49SNicolin Chen spin_lock_irqsave(&ctrl->ctl_lock, flags);
862a2388a49SNicolin Chen if (ctrl->ready_buf) {
863a2388a49SNicolin Chen int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE;
864a2388a49SNicolin Chen memcpy(&ucontrol->value.iec958.subcode[0],
865a2388a49SNicolin Chen &ctrl->subcode[idx], SPDIF_UBITS_SIZE);
866f3a30baaSNicolin Chen ret = 0;
867a2388a49SNicolin Chen }
868a2388a49SNicolin Chen spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
869a2388a49SNicolin Chen
870a2388a49SNicolin Chen return ret;
871a2388a49SNicolin Chen }
872a2388a49SNicolin Chen
873dcfcf2c2SXiubo Li /* Q-subcode information. The byte size is SPDIF_UBITS_SIZE/8 */
fsl_spdif_qinfo(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)874a2388a49SNicolin Chen static int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol,
875a2388a49SNicolin Chen struct snd_ctl_elem_info *uinfo)
876a2388a49SNicolin Chen {
877a2388a49SNicolin Chen uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
878a2388a49SNicolin Chen uinfo->count = SPDIF_QSUB_SIZE;
879a2388a49SNicolin Chen
880a2388a49SNicolin Chen return 0;
881a2388a49SNicolin Chen }
882a2388a49SNicolin Chen
883a2388a49SNicolin Chen /* Get Q subcode from chip value which readed out in QChannel register */
fsl_spdif_qget(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)884a2388a49SNicolin Chen static int fsl_spdif_qget(struct snd_kcontrol *kcontrol,
885a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
886a2388a49SNicolin Chen {
887a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
888a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
889a2388a49SNicolin Chen struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control;
890a2388a49SNicolin Chen unsigned long flags;
891f3a30baaSNicolin Chen int ret = -EAGAIN;
892a2388a49SNicolin Chen
893a2388a49SNicolin Chen spin_lock_irqsave(&ctrl->ctl_lock, flags);
894a2388a49SNicolin Chen if (ctrl->ready_buf) {
895a2388a49SNicolin Chen int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE;
896a2388a49SNicolin Chen memcpy(&ucontrol->value.bytes.data[0],
897a2388a49SNicolin Chen &ctrl->qsub[idx], SPDIF_QSUB_SIZE);
898f3a30baaSNicolin Chen ret = 0;
899a2388a49SNicolin Chen }
900a2388a49SNicolin Chen spin_unlock_irqrestore(&ctrl->ctl_lock, flags);
901a2388a49SNicolin Chen
902a2388a49SNicolin Chen return ret;
903a2388a49SNicolin Chen }
904a2388a49SNicolin Chen
905a2388a49SNicolin Chen /* Get valid good bit from interrupt status register */
fsl_spdif_rx_vbit_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)906aa3fce5cSShengjiu Wang static int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol,
907a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
908a2388a49SNicolin Chen {
909a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
910a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
911a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
912a2388a49SNicolin Chen u32 val;
913a2388a49SNicolin Chen
914e9b383dcSNicolin Chen regmap_read(regmap, REG_SPDIF_SIS, &val);
915a2388a49SNicolin Chen ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0;
916a2388a49SNicolin Chen regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD);
917a2388a49SNicolin Chen
918a2388a49SNicolin Chen return 0;
919a2388a49SNicolin Chen }
920a2388a49SNicolin Chen
fsl_spdif_tx_vbit_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)921aa3fce5cSShengjiu Wang static int fsl_spdif_tx_vbit_get(struct snd_kcontrol *kcontrol,
922aa3fce5cSShengjiu Wang struct snd_ctl_elem_value *ucontrol)
923aa3fce5cSShengjiu Wang {
924aa3fce5cSShengjiu Wang struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
925aa3fce5cSShengjiu Wang struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
926aa3fce5cSShengjiu Wang struct regmap *regmap = spdif_priv->regmap;
927aa3fce5cSShengjiu Wang u32 val;
928aa3fce5cSShengjiu Wang
929aa3fce5cSShengjiu Wang regmap_read(regmap, REG_SPDIF_SCR, &val);
930aa3fce5cSShengjiu Wang val = (val & SCR_VAL_MASK) >> SCR_VAL_OFFSET;
931aa3fce5cSShengjiu Wang val = 1 - val;
932aa3fce5cSShengjiu Wang ucontrol->value.integer.value[0] = val;
933aa3fce5cSShengjiu Wang
934aa3fce5cSShengjiu Wang return 0;
935aa3fce5cSShengjiu Wang }
936aa3fce5cSShengjiu Wang
fsl_spdif_tx_vbit_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)937aa3fce5cSShengjiu Wang static int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol,
938aa3fce5cSShengjiu Wang struct snd_ctl_elem_value *ucontrol)
939aa3fce5cSShengjiu Wang {
940aa3fce5cSShengjiu Wang struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
941aa3fce5cSShengjiu Wang struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
942aa3fce5cSShengjiu Wang struct regmap *regmap = spdif_priv->regmap;
943aa3fce5cSShengjiu Wang u32 val = (1 - ucontrol->value.integer.value[0]) << SCR_VAL_OFFSET;
944aa3fce5cSShengjiu Wang
945aa3fce5cSShengjiu Wang regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_VAL_MASK, val);
946aa3fce5cSShengjiu Wang
947aa3fce5cSShengjiu Wang return 0;
948aa3fce5cSShengjiu Wang }
949aa3fce5cSShengjiu Wang
fsl_spdif_rx_rcm_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)950604e5178SViorel Suman static int fsl_spdif_rx_rcm_get(struct snd_kcontrol *kcontrol,
951604e5178SViorel Suman struct snd_ctl_elem_value *ucontrol)
952604e5178SViorel Suman {
953604e5178SViorel Suman struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
954604e5178SViorel Suman struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
955604e5178SViorel Suman struct regmap *regmap = spdif_priv->regmap;
956604e5178SViorel Suman u32 val;
957604e5178SViorel Suman
958604e5178SViorel Suman regmap_read(regmap, REG_SPDIF_SCR, &val);
959604e5178SViorel Suman val = (val & SCR_RAW_CAPTURE_MODE) ? 1 : 0;
960604e5178SViorel Suman ucontrol->value.integer.value[0] = val;
961604e5178SViorel Suman
962604e5178SViorel Suman return 0;
963604e5178SViorel Suman }
964604e5178SViorel Suman
fsl_spdif_rx_rcm_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)965604e5178SViorel Suman static int fsl_spdif_rx_rcm_put(struct snd_kcontrol *kcontrol,
966604e5178SViorel Suman struct snd_ctl_elem_value *ucontrol)
967604e5178SViorel Suman {
968604e5178SViorel Suman struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
969604e5178SViorel Suman struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
970604e5178SViorel Suman struct regmap *regmap = spdif_priv->regmap;
971604e5178SViorel Suman u32 val = (ucontrol->value.integer.value[0] ? SCR_RAW_CAPTURE_MODE : 0);
972604e5178SViorel Suman
973604e5178SViorel Suman if (val)
974604e5178SViorel Suman cpu_dai->driver->capture.formats |= SNDRV_PCM_FMTBIT_S32_LE;
975604e5178SViorel Suman else
976604e5178SViorel Suman cpu_dai->driver->capture.formats &= ~SNDRV_PCM_FMTBIT_S32_LE;
977604e5178SViorel Suman
978604e5178SViorel Suman regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_RAW_CAPTURE_MODE, val);
979604e5178SViorel Suman
980604e5178SViorel Suman return 0;
981604e5178SViorel Suman }
982604e5178SViorel Suman
fsl_spdif_bypass_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)98383bea088SViorel Suman static int fsl_spdif_bypass_get(struct snd_kcontrol *kcontrol,
98483bea088SViorel Suman struct snd_ctl_elem_value *ucontrol)
98583bea088SViorel Suman {
98683bea088SViorel Suman struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
98783bea088SViorel Suman struct fsl_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
98883bea088SViorel Suman
98983bea088SViorel Suman ucontrol->value.integer.value[0] = priv->bypass ? 1 : 0;
99083bea088SViorel Suman
99183bea088SViorel Suman return 0;
99283bea088SViorel Suman }
99383bea088SViorel Suman
fsl_spdif_bypass_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)99483bea088SViorel Suman static int fsl_spdif_bypass_put(struct snd_kcontrol *kcontrol,
99583bea088SViorel Suman struct snd_ctl_elem_value *ucontrol)
99683bea088SViorel Suman {
99783bea088SViorel Suman struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol);
99883bea088SViorel Suman struct fsl_spdif_priv *priv = snd_soc_dai_get_drvdata(dai);
99983bea088SViorel Suman struct snd_soc_card *card = dai->component->card;
100083bea088SViorel Suman bool set = (ucontrol->value.integer.value[0] != 0);
100183bea088SViorel Suman struct regmap *regmap = priv->regmap;
100283bea088SViorel Suman struct snd_soc_pcm_runtime *rtd;
100383bea088SViorel Suman u32 scr, mask;
100483bea088SViorel Suman int stream;
100583bea088SViorel Suman
100683bea088SViorel Suman rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
100783bea088SViorel Suman
100883bea088SViorel Suman if (priv->bypass == set)
100983bea088SViorel Suman return 0; /* nothing to do */
101083bea088SViorel Suman
101183bea088SViorel Suman if (snd_soc_dai_active(dai)) {
101283bea088SViorel Suman dev_err(dai->dev, "Cannot change BYPASS mode while stream is running.\n");
101383bea088SViorel Suman return -EBUSY;
101483bea088SViorel Suman }
101583bea088SViorel Suman
101683bea088SViorel Suman pm_runtime_get_sync(dai->dev);
101783bea088SViorel Suman
101883bea088SViorel Suman if (set) {
101983bea088SViorel Suman /* Disable interrupts */
102083bea088SViorel Suman regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0);
102183bea088SViorel Suman
102283bea088SViorel Suman /* Configure BYPASS mode */
102383bea088SViorel Suman scr = SCR_TXSEL_RX | SCR_RXFIFO_OFF;
102483bea088SViorel Suman mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK |
102583bea088SViorel Suman SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK | SCR_TXSEL_MASK;
102683bea088SViorel Suman /* Power up SPDIF module */
102783bea088SViorel Suman mask |= SCR_LOW_POWER;
102883bea088SViorel Suman } else {
102983bea088SViorel Suman /* Power down SPDIF module, disable TX */
103083bea088SViorel Suman scr = SCR_LOW_POWER | SCR_TXSEL_OFF;
103183bea088SViorel Suman mask = SCR_LOW_POWER | SCR_TXSEL_MASK;
103283bea088SViorel Suman }
103383bea088SViorel Suman
103483bea088SViorel Suman regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr);
103583bea088SViorel Suman
103683bea088SViorel Suman /* Disable playback & capture if BYPASS mode is enabled, enable otherwise */
103783bea088SViorel Suman for_each_pcm_streams(stream)
103883bea088SViorel Suman rtd->pcm->streams[stream].substream_count = (set ? 0 : 1);
103983bea088SViorel Suman
104083bea088SViorel Suman priv->bypass = set;
104183bea088SViorel Suman pm_runtime_put_sync(dai->dev);
104283bea088SViorel Suman
104383bea088SViorel Suman return 0;
104483bea088SViorel Suman }
104583bea088SViorel Suman
1046dcfcf2c2SXiubo Li /* DPLL lock information */
fsl_spdif_rxrate_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)1047a2388a49SNicolin Chen static int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol,
1048a2388a49SNicolin Chen struct snd_ctl_elem_info *uinfo)
1049a2388a49SNicolin Chen {
1050a2388a49SNicolin Chen uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1051a2388a49SNicolin Chen uinfo->count = 1;
1052a2388a49SNicolin Chen uinfo->value.integer.min = 16000;
10531bfa3eaaSShengjiu Wang uinfo->value.integer.max = 192000;
1054a2388a49SNicolin Chen
1055a2388a49SNicolin Chen return 0;
1056a2388a49SNicolin Chen }
1057a2388a49SNicolin Chen
1058a2388a49SNicolin Chen static u32 gainsel_multi[GAINSEL_MULTI_MAX] = {
1059a2388a49SNicolin Chen 24, 16, 12, 8, 6, 4, 3,
1060a2388a49SNicolin Chen };
1061a2388a49SNicolin Chen
1062a2388a49SNicolin Chen /* Get RX data clock rate given the SPDIF bus_clk */
spdif_get_rxclk_rate(struct fsl_spdif_priv * spdif_priv,enum spdif_gainsel gainsel)1063a2388a49SNicolin Chen static int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv,
1064a2388a49SNicolin Chen enum spdif_gainsel gainsel)
1065a2388a49SNicolin Chen {
1066a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
1067a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
1068a2388a49SNicolin Chen u64 tmpval64, busclk_freq = 0;
1069a2388a49SNicolin Chen u32 freqmeas, phaseconf;
1070a2388a49SNicolin Chen u8 clksrc;
1071a2388a49SNicolin Chen
1072a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas);
1073a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf);
1074a2388a49SNicolin Chen
1075a2388a49SNicolin Chen clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf;
1076f3a30baaSNicolin Chen
1077a2388a49SNicolin Chen /* Get bus clock from system */
1078f3a30baaSNicolin Chen if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED))
10790b864390SNicolin Chen busclk_freq = clk_get_rate(spdif_priv->sysclk);
1080a2388a49SNicolin Chen
1081a2388a49SNicolin Chen /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */
1082a2388a49SNicolin Chen tmpval64 = (u64) busclk_freq * freqmeas;
1083a2388a49SNicolin Chen do_div(tmpval64, gainsel_multi[gainsel] * 1024);
1084a2388a49SNicolin Chen do_div(tmpval64, 128 * 1024);
1085a2388a49SNicolin Chen
1086a2388a49SNicolin Chen dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas);
1087a2388a49SNicolin Chen dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq);
1088a2388a49SNicolin Chen dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64);
1089a2388a49SNicolin Chen
1090a2388a49SNicolin Chen return (int)tmpval64;
1091a2388a49SNicolin Chen }
1092a2388a49SNicolin Chen
1093a2388a49SNicolin Chen /*
1094a2388a49SNicolin Chen * Get DPLL lock or not info from stable interrupt status register.
1095a2388a49SNicolin Chen * User application must use this control to get locked,
1096a2388a49SNicolin Chen * then can do next PCM operation
1097a2388a49SNicolin Chen */
fsl_spdif_rxrate_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1098a2388a49SNicolin Chen static int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol,
1099a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
1100a2388a49SNicolin Chen {
1101a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
1102a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
1103f3a30baaSNicolin Chen int rate = 0;
1104a2388a49SNicolin Chen
1105a2388a49SNicolin Chen if (spdif_priv->dpll_locked)
1106f3a30baaSNicolin Chen rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL);
1107f3a30baaSNicolin Chen
1108a2388a49SNicolin Chen ucontrol->value.integer.value[0] = rate;
1109a2388a49SNicolin Chen
1110a2388a49SNicolin Chen return 0;
1111a2388a49SNicolin Chen }
1112a2388a49SNicolin Chen
1113a2388a49SNicolin Chen /*
1114a2388a49SNicolin Chen * User bit sync mode:
1115a2388a49SNicolin Chen * 1 CD User channel subcode
1116a2388a49SNicolin Chen * 0 Non-CD data
1117a2388a49SNicolin Chen */
fsl_spdif_usync_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1118a2388a49SNicolin Chen static int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol,
1119a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
1120a2388a49SNicolin Chen {
1121a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
1122a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
1123a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
1124a2388a49SNicolin Chen u32 val;
1125a2388a49SNicolin Chen
1126a2388a49SNicolin Chen regmap_read(regmap, REG_SPDIF_SRCD, &val);
1127a2388a49SNicolin Chen ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0;
1128a2388a49SNicolin Chen
1129a2388a49SNicolin Chen return 0;
1130a2388a49SNicolin Chen }
1131a2388a49SNicolin Chen
1132a2388a49SNicolin Chen /*
1133a2388a49SNicolin Chen * User bit sync mode:
1134a2388a49SNicolin Chen * 1 CD User channel subcode
1135a2388a49SNicolin Chen * 0 Non-CD data
1136a2388a49SNicolin Chen */
fsl_spdif_usync_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)1137a2388a49SNicolin Chen static int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol,
1138a2388a49SNicolin Chen struct snd_ctl_elem_value *ucontrol)
1139a2388a49SNicolin Chen {
1140a2388a49SNicolin Chen struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol);
1141a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai);
1142a2388a49SNicolin Chen struct regmap *regmap = spdif_priv->regmap;
1143a2388a49SNicolin Chen u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET;
1144a2388a49SNicolin Chen
1145a2388a49SNicolin Chen regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val);
1146a2388a49SNicolin Chen
1147a2388a49SNicolin Chen return 0;
1148a2388a49SNicolin Chen }
1149a2388a49SNicolin Chen
1150a2388a49SNicolin Chen /* FSL SPDIF IEC958 controller defines */
1151a2388a49SNicolin Chen static struct snd_kcontrol_new fsl_spdif_ctrls[] = {
1152a2388a49SNicolin Chen /* Status cchanel controller */
1153a2388a49SNicolin Chen {
1154a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1155a2388a49SNicolin Chen .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT),
1156a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1157a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_WRITE |
1158a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1159a2388a49SNicolin Chen .info = fsl_spdif_info,
1160a2388a49SNicolin Chen .get = fsl_spdif_pb_get,
1161a2388a49SNicolin Chen .put = fsl_spdif_pb_put,
1162a2388a49SNicolin Chen },
1163a2388a49SNicolin Chen {
1164a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1165a2388a49SNicolin Chen .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT),
1166a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1167a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1168a2388a49SNicolin Chen .info = fsl_spdif_info,
1169a2388a49SNicolin Chen .get = fsl_spdif_capture_get,
1170a2388a49SNicolin Chen },
1171a2388a49SNicolin Chen /* User bits controller */
1172a2388a49SNicolin Chen {
1173a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1174a2388a49SNicolin Chen .name = "IEC958 Subcode Capture Default",
1175a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1176a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1177a2388a49SNicolin Chen .info = fsl_spdif_info,
1178a2388a49SNicolin Chen .get = fsl_spdif_subcode_get,
1179a2388a49SNicolin Chen },
1180a2388a49SNicolin Chen {
1181a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1182a2388a49SNicolin Chen .name = "IEC958 Q-subcode Capture Default",
1183a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1184a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1185a2388a49SNicolin Chen .info = fsl_spdif_qinfo,
1186a2388a49SNicolin Chen .get = fsl_spdif_qget,
1187a2388a49SNicolin Chen },
1188a2388a49SNicolin Chen /* Valid bit error controller */
1189a2388a49SNicolin Chen {
1190a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1191aa3fce5cSShengjiu Wang .name = "IEC958 RX V-Bit Errors",
1192a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1193a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
11946ad864edSViorel Suman .info = snd_ctl_boolean_mono_info,
1195aa3fce5cSShengjiu Wang .get = fsl_spdif_rx_vbit_get,
1196aa3fce5cSShengjiu Wang },
1197aa3fce5cSShengjiu Wang {
1198aa3fce5cSShengjiu Wang .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1199aa3fce5cSShengjiu Wang .name = "IEC958 TX V-Bit",
1200aa3fce5cSShengjiu Wang .access = SNDRV_CTL_ELEM_ACCESS_READ |
1201aa3fce5cSShengjiu Wang SNDRV_CTL_ELEM_ACCESS_WRITE |
1202aa3fce5cSShengjiu Wang SNDRV_CTL_ELEM_ACCESS_VOLATILE,
12036ad864edSViorel Suman .info = snd_ctl_boolean_mono_info,
1204aa3fce5cSShengjiu Wang .get = fsl_spdif_tx_vbit_get,
1205aa3fce5cSShengjiu Wang .put = fsl_spdif_tx_vbit_put,
1206a2388a49SNicolin Chen },
1207a2388a49SNicolin Chen /* DPLL lock info get controller */
1208a2388a49SNicolin Chen {
1209a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1210e31a4a93SRobert Rosengren .name = RX_SAMPLE_RATE_KCONTROL,
1211a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1212a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1213a2388a49SNicolin Chen .info = fsl_spdif_rxrate_info,
1214a2388a49SNicolin Chen .get = fsl_spdif_rxrate_get,
1215a2388a49SNicolin Chen },
121683bea088SViorel Suman /* RX bypass controller */
121783bea088SViorel Suman {
121883bea088SViorel Suman .iface = SNDRV_CTL_ELEM_IFACE_PCM,
121983bea088SViorel Suman .name = "Bypass Mode",
122083bea088SViorel Suman .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
122183bea088SViorel Suman .info = snd_ctl_boolean_mono_info,
122283bea088SViorel Suman .get = fsl_spdif_bypass_get,
122383bea088SViorel Suman .put = fsl_spdif_bypass_put,
122483bea088SViorel Suman },
1225a2388a49SNicolin Chen /* User bit sync mode set/get controller */
1226a2388a49SNicolin Chen {
1227a2388a49SNicolin Chen .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1228a2388a49SNicolin Chen .name = "IEC958 USyncMode CDText",
1229a2388a49SNicolin Chen .access = SNDRV_CTL_ELEM_ACCESS_READ |
1230a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_WRITE |
1231a2388a49SNicolin Chen SNDRV_CTL_ELEM_ACCESS_VOLATILE,
12326ad864edSViorel Suman .info = snd_ctl_boolean_mono_info,
1233a2388a49SNicolin Chen .get = fsl_spdif_usync_get,
1234a2388a49SNicolin Chen .put = fsl_spdif_usync_put,
1235a2388a49SNicolin Chen },
1236a2388a49SNicolin Chen };
1237a2388a49SNicolin Chen
1238604e5178SViorel Suman static struct snd_kcontrol_new fsl_spdif_ctrls_rcm[] = {
1239604e5178SViorel Suman {
1240604e5178SViorel Suman .iface = SNDRV_CTL_ELEM_IFACE_PCM,
1241604e5178SViorel Suman .name = "IEC958 Raw Capture Mode",
1242604e5178SViorel Suman .access = SNDRV_CTL_ELEM_ACCESS_READ |
1243604e5178SViorel Suman SNDRV_CTL_ELEM_ACCESS_WRITE |
1244604e5178SViorel Suman SNDRV_CTL_ELEM_ACCESS_VOLATILE,
1245604e5178SViorel Suman .info = snd_ctl_boolean_mono_info,
1246604e5178SViorel Suman .get = fsl_spdif_rx_rcm_get,
1247604e5178SViorel Suman .put = fsl_spdif_rx_rcm_put,
1248604e5178SViorel Suman },
1249604e5178SViorel Suman };
1250604e5178SViorel Suman
fsl_spdif_dai_probe(struct snd_soc_dai * dai)1251a2388a49SNicolin Chen static int fsl_spdif_dai_probe(struct snd_soc_dai *dai)
1252a2388a49SNicolin Chen {
1253a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai);
1254a2388a49SNicolin Chen
125505cf482dSXiubo Li snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx,
125605cf482dSXiubo Li &spdif_private->dma_params_rx);
1257a2388a49SNicolin Chen
1258a2388a49SNicolin Chen snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls));
1259a2388a49SNicolin Chen
1260604e5178SViorel Suman if (spdif_private->soc->raw_capture_mode)
1261604e5178SViorel Suman snd_soc_add_dai_controls(dai, fsl_spdif_ctrls_rcm,
1262604e5178SViorel Suman ARRAY_SIZE(fsl_spdif_ctrls_rcm));
1263604e5178SViorel Suman
1264e31a4a93SRobert Rosengren spdif_private->snd_card = dai->component->card->snd_card;
1265e31a4a93SRobert Rosengren spdif_private->rxrate_kcontrol = snd_soc_card_get_kcontrol(dai->component->card,
1266e31a4a93SRobert Rosengren RX_SAMPLE_RATE_KCONTROL);
1267e31a4a93SRobert Rosengren if (!spdif_private->rxrate_kcontrol)
1268e31a4a93SRobert Rosengren dev_err(&spdif_private->pdev->dev, "failed to get %s kcontrol\n",
1269e31a4a93SRobert Rosengren RX_SAMPLE_RATE_KCONTROL);
1270e31a4a93SRobert Rosengren
1271055b0821SShengjiu Wang /*Clear the val bit for Tx*/
1272055b0821SShengjiu Wang regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR,
1273055b0821SShengjiu Wang SCR_VAL_MASK, SCR_VAL_CLEAR);
1274055b0821SShengjiu Wang
1275a2388a49SNicolin Chen return 0;
1276a2388a49SNicolin Chen }
1277a2388a49SNicolin Chen
1278*ac27ca16SKuninori Morimoto static const struct snd_soc_dai_ops fsl_spdif_dai_ops = {
1279*ac27ca16SKuninori Morimoto .probe = fsl_spdif_dai_probe,
1280*ac27ca16SKuninori Morimoto .startup = fsl_spdif_startup,
1281*ac27ca16SKuninori Morimoto .hw_params = fsl_spdif_hw_params,
1282*ac27ca16SKuninori Morimoto .trigger = fsl_spdif_trigger,
1283*ac27ca16SKuninori Morimoto .shutdown = fsl_spdif_shutdown,
1284*ac27ca16SKuninori Morimoto };
1285*ac27ca16SKuninori Morimoto
12866b4c80f9SMark Brown static struct snd_soc_dai_driver fsl_spdif_dai = {
1287a2388a49SNicolin Chen .playback = {
128875640932SNicolin Chen .stream_name = "CPU-Playback",
1289a2388a49SNicolin Chen .channels_min = 2,
1290a2388a49SNicolin Chen .channels_max = 2,
1291a2388a49SNicolin Chen .rates = FSL_SPDIF_RATES_PLAYBACK,
1292a2388a49SNicolin Chen .formats = FSL_SPDIF_FORMATS_PLAYBACK,
1293a2388a49SNicolin Chen },
1294a2388a49SNicolin Chen .capture = {
129575640932SNicolin Chen .stream_name = "CPU-Capture",
1296a2388a49SNicolin Chen .channels_min = 2,
1297a2388a49SNicolin Chen .channels_max = 2,
1298a2388a49SNicolin Chen .rates = FSL_SPDIF_RATES_CAPTURE,
1299a2388a49SNicolin Chen .formats = FSL_SPDIF_FORMATS_CAPTURE,
1300a2388a49SNicolin Chen },
1301a2388a49SNicolin Chen .ops = &fsl_spdif_dai_ops,
1302a2388a49SNicolin Chen };
1303a2388a49SNicolin Chen
1304a2388a49SNicolin Chen static const struct snd_soc_component_driver fsl_spdif_component = {
1305a2388a49SNicolin Chen .name = "fsl-spdif",
13061e63fcc7SCharles Keepax .legacy_dai_naming = 1,
1307a2388a49SNicolin Chen };
1308a2388a49SNicolin Chen
13096d22db43SFabio Estevam /* FSL SPDIF REGMAP */
1310f9f4fa61SZidan Wang static const struct reg_default fsl_spdif_reg_defaults[] = {
13119f1206dcSZidan Wang {REG_SPDIF_SCR, 0x00000400},
13129f1206dcSZidan Wang {REG_SPDIF_SRCD, 0x00000000},
13139f1206dcSZidan Wang {REG_SPDIF_SIE, 0x00000000},
13149f1206dcSZidan Wang {REG_SPDIF_STL, 0x00000000},
13159f1206dcSZidan Wang {REG_SPDIF_STR, 0x00000000},
13169f1206dcSZidan Wang {REG_SPDIF_STCSCH, 0x00000000},
13179f1206dcSZidan Wang {REG_SPDIF_STCSCL, 0x00000000},
1318638cec39SShengjiu Wang {REG_SPDIF_STCSPH, 0x00000000},
1319638cec39SShengjiu Wang {REG_SPDIF_STCSPL, 0x00000000},
13209f1206dcSZidan Wang {REG_SPDIF_STC, 0x00020f00},
1321f9f4fa61SZidan Wang };
1322a2388a49SNicolin Chen
fsl_spdif_readable_reg(struct device * dev,unsigned int reg)1323a2388a49SNicolin Chen static bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg)
1324a2388a49SNicolin Chen {
1325a2388a49SNicolin Chen switch (reg) {
1326a2388a49SNicolin Chen case REG_SPDIF_SCR:
1327a2388a49SNicolin Chen case REG_SPDIF_SRCD:
1328a2388a49SNicolin Chen case REG_SPDIF_SRPC:
1329a2388a49SNicolin Chen case REG_SPDIF_SIE:
1330a2388a49SNicolin Chen case REG_SPDIF_SIS:
1331a2388a49SNicolin Chen case REG_SPDIF_SRL:
1332a2388a49SNicolin Chen case REG_SPDIF_SRR:
1333a2388a49SNicolin Chen case REG_SPDIF_SRCSH:
1334a2388a49SNicolin Chen case REG_SPDIF_SRCSL:
1335a2388a49SNicolin Chen case REG_SPDIF_SRU:
1336a2388a49SNicolin Chen case REG_SPDIF_SRQ:
1337a2388a49SNicolin Chen case REG_SPDIF_STCSCH:
1338a2388a49SNicolin Chen case REG_SPDIF_STCSCL:
1339638cec39SShengjiu Wang case REG_SPDIF_STCSPH:
1340638cec39SShengjiu Wang case REG_SPDIF_STCSPL:
1341a2388a49SNicolin Chen case REG_SPDIF_SRFM:
1342a2388a49SNicolin Chen case REG_SPDIF_STC:
1343638cec39SShengjiu Wang case REG_SPDIF_SRCCA_31_0:
1344638cec39SShengjiu Wang case REG_SPDIF_SRCCA_63_32:
1345638cec39SShengjiu Wang case REG_SPDIF_SRCCA_95_64:
1346638cec39SShengjiu Wang case REG_SPDIF_SRCCA_127_96:
1347638cec39SShengjiu Wang case REG_SPDIF_SRCCA_159_128:
1348638cec39SShengjiu Wang case REG_SPDIF_SRCCA_191_160:
1349638cec39SShengjiu Wang case REG_SPDIF_STCCA_31_0:
1350638cec39SShengjiu Wang case REG_SPDIF_STCCA_63_32:
1351638cec39SShengjiu Wang case REG_SPDIF_STCCA_95_64:
1352638cec39SShengjiu Wang case REG_SPDIF_STCCA_127_96:
1353638cec39SShengjiu Wang case REG_SPDIF_STCCA_159_128:
1354638cec39SShengjiu Wang case REG_SPDIF_STCCA_191_160:
1355a2388a49SNicolin Chen return true;
1356a2388a49SNicolin Chen default:
1357a2388a49SNicolin Chen return false;
1358e19bcb6bSSachin Kamat }
1359a2388a49SNicolin Chen }
1360a2388a49SNicolin Chen
fsl_spdif_volatile_reg(struct device * dev,unsigned int reg)1361f9f4fa61SZidan Wang static bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg)
1362f9f4fa61SZidan Wang {
1363f9f4fa61SZidan Wang switch (reg) {
1364f9f4fa61SZidan Wang case REG_SPDIF_SRPC:
1365f9f4fa61SZidan Wang case REG_SPDIF_SIS:
1366f9f4fa61SZidan Wang case REG_SPDIF_SRL:
1367f9f4fa61SZidan Wang case REG_SPDIF_SRR:
1368f9f4fa61SZidan Wang case REG_SPDIF_SRCSH:
1369f9f4fa61SZidan Wang case REG_SPDIF_SRCSL:
1370f9f4fa61SZidan Wang case REG_SPDIF_SRU:
1371f9f4fa61SZidan Wang case REG_SPDIF_SRQ:
1372f9f4fa61SZidan Wang case REG_SPDIF_SRFM:
1373638cec39SShengjiu Wang case REG_SPDIF_SRCCA_31_0:
1374638cec39SShengjiu Wang case REG_SPDIF_SRCCA_63_32:
1375638cec39SShengjiu Wang case REG_SPDIF_SRCCA_95_64:
1376638cec39SShengjiu Wang case REG_SPDIF_SRCCA_127_96:
1377638cec39SShengjiu Wang case REG_SPDIF_SRCCA_159_128:
1378638cec39SShengjiu Wang case REG_SPDIF_SRCCA_191_160:
1379f9f4fa61SZidan Wang return true;
1380f9f4fa61SZidan Wang default:
1381f9f4fa61SZidan Wang return false;
1382f9f4fa61SZidan Wang }
1383f9f4fa61SZidan Wang }
1384f9f4fa61SZidan Wang
fsl_spdif_writeable_reg(struct device * dev,unsigned int reg)1385a2388a49SNicolin Chen static bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg)
1386a2388a49SNicolin Chen {
1387a2388a49SNicolin Chen switch (reg) {
1388a2388a49SNicolin Chen case REG_SPDIF_SCR:
1389a2388a49SNicolin Chen case REG_SPDIF_SRCD:
1390a2388a49SNicolin Chen case REG_SPDIF_SRPC:
1391a2388a49SNicolin Chen case REG_SPDIF_SIE:
1392a2388a49SNicolin Chen case REG_SPDIF_SIC:
1393a2388a49SNicolin Chen case REG_SPDIF_STL:
1394a2388a49SNicolin Chen case REG_SPDIF_STR:
1395a2388a49SNicolin Chen case REG_SPDIF_STCSCH:
1396a2388a49SNicolin Chen case REG_SPDIF_STCSCL:
1397638cec39SShengjiu Wang case REG_SPDIF_STCSPH:
1398638cec39SShengjiu Wang case REG_SPDIF_STCSPL:
1399a2388a49SNicolin Chen case REG_SPDIF_STC:
1400638cec39SShengjiu Wang case REG_SPDIF_STCCA_31_0:
1401638cec39SShengjiu Wang case REG_SPDIF_STCCA_63_32:
1402638cec39SShengjiu Wang case REG_SPDIF_STCCA_95_64:
1403638cec39SShengjiu Wang case REG_SPDIF_STCCA_127_96:
1404638cec39SShengjiu Wang case REG_SPDIF_STCCA_159_128:
1405638cec39SShengjiu Wang case REG_SPDIF_STCCA_191_160:
1406a2388a49SNicolin Chen return true;
1407a2388a49SNicolin Chen default:
1408a2388a49SNicolin Chen return false;
1409e19bcb6bSSachin Kamat }
1410a2388a49SNicolin Chen }
1411a2388a49SNicolin Chen
141266491507SXiubo Li static const struct regmap_config fsl_spdif_regmap_config = {
1413a2388a49SNicolin Chen .reg_bits = 32,
1414a2388a49SNicolin Chen .reg_stride = 4,
1415a2388a49SNicolin Chen .val_bits = 32,
1416a2388a49SNicolin Chen
1417638cec39SShengjiu Wang .max_register = REG_SPDIF_STCCA_191_160,
1418f9f4fa61SZidan Wang .reg_defaults = fsl_spdif_reg_defaults,
1419f9f4fa61SZidan Wang .num_reg_defaults = ARRAY_SIZE(fsl_spdif_reg_defaults),
1420a2388a49SNicolin Chen .readable_reg = fsl_spdif_readable_reg,
1421f9f4fa61SZidan Wang .volatile_reg = fsl_spdif_volatile_reg,
1422a2388a49SNicolin Chen .writeable_reg = fsl_spdif_writeable_reg,
142335ddb157SMarek Vasut .cache_type = REGCACHE_FLAT,
1424a2388a49SNicolin Chen };
1425a2388a49SNicolin Chen
fsl_spdif_txclk_caldiv(struct fsl_spdif_priv * spdif_priv,struct clk * clk,u64 savesub,enum spdif_txrate index,bool round)1426a2388a49SNicolin Chen static u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv,
1427a2388a49SNicolin Chen struct clk *clk, u64 savesub,
14289c6344b3SNicolin Chen enum spdif_txrate index, bool round)
1429a2388a49SNicolin Chen {
143065bc25b8SMatus Gajdos static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400,
14311bfa3eaaSShengjiu Wang 192000, };
143281efec85SShawn Guo bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk);
1433a2388a49SNicolin Chen u64 rate_ideal, rate_actual, sub;
14342231609aSViorel Suman u32 arate;
14352231609aSViorel Suman u16 sysclk_dfmin, sysclk_dfmax, sysclk_df;
14362231609aSViorel Suman u8 txclk_df;
1437a2388a49SNicolin Chen
143827c647bfSNicolin Chen /* The sysclk has an extra divisor [2, 512] */
143927c647bfSNicolin Chen sysclk_dfmin = is_sysclk ? 2 : 1;
144027c647bfSNicolin Chen sysclk_dfmax = is_sysclk ? 512 : 1;
144127c647bfSNicolin Chen
144227c647bfSNicolin Chen for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) {
1443e41a4a79SNicolin Chen for (txclk_df = 1; txclk_df <= 128; txclk_df++) {
1444b999a7a9SGustavo A. R. Silva rate_ideal = rate[index] * txclk_df * 64ULL;
14459c6344b3SNicolin Chen if (round)
1446a2388a49SNicolin Chen rate_actual = clk_round_rate(clk, rate_ideal);
14479c6344b3SNicolin Chen else
14489c6344b3SNicolin Chen rate_actual = clk_get_rate(clk);
1449a2388a49SNicolin Chen
1450a2388a49SNicolin Chen arate = rate_actual / 64;
145127c647bfSNicolin Chen arate /= txclk_df * sysclk_df;
1452a2388a49SNicolin Chen
1453a2388a49SNicolin Chen if (arate == rate[index]) {
1454a2388a49SNicolin Chen /* We are lucky */
1455a2388a49SNicolin Chen savesub = 0;
1456e41a4a79SNicolin Chen spdif_priv->txclk_df[index] = txclk_df;
145727c647bfSNicolin Chen spdif_priv->sysclk_df[index] = sysclk_df;
1458527cda78SNicolin Chen spdif_priv->txrate[index] = arate;
145927c647bfSNicolin Chen goto out;
1460a2388a49SNicolin Chen } else if (arate / rate[index] == 1) {
1461a2388a49SNicolin Chen /* A little bigger than expect */
1462c89c7e94SAnssi Hannula sub = (u64)(arate - rate[index]) * 100000;
1463a2388a49SNicolin Chen do_div(sub, rate[index]);
146427c647bfSNicolin Chen if (sub >= savesub)
146527c647bfSNicolin Chen continue;
1466a2388a49SNicolin Chen savesub = sub;
1467e41a4a79SNicolin Chen spdif_priv->txclk_df[index] = txclk_df;
146827c647bfSNicolin Chen spdif_priv->sysclk_df[index] = sysclk_df;
1469527cda78SNicolin Chen spdif_priv->txrate[index] = arate;
1470a2388a49SNicolin Chen } else if (rate[index] / arate == 1) {
1471a2388a49SNicolin Chen /* A little smaller than expect */
1472c89c7e94SAnssi Hannula sub = (u64)(rate[index] - arate) * 100000;
1473a2388a49SNicolin Chen do_div(sub, rate[index]);
147427c647bfSNicolin Chen if (sub >= savesub)
147527c647bfSNicolin Chen continue;
1476a2388a49SNicolin Chen savesub = sub;
1477e41a4a79SNicolin Chen spdif_priv->txclk_df[index] = txclk_df;
147827c647bfSNicolin Chen spdif_priv->sysclk_df[index] = sysclk_df;
1479527cda78SNicolin Chen spdif_priv->txrate[index] = arate;
1480a2388a49SNicolin Chen }
1481a2388a49SNicolin Chen }
1482a2388a49SNicolin Chen }
1483a2388a49SNicolin Chen
148427c647bfSNicolin Chen out:
1485a2388a49SNicolin Chen return savesub;
1486a2388a49SNicolin Chen }
1487a2388a49SNicolin Chen
fsl_spdif_probe_txclk(struct fsl_spdif_priv * spdif_priv,enum spdif_txrate index)1488a2388a49SNicolin Chen static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv,
1489a2388a49SNicolin Chen enum spdif_txrate index)
1490a2388a49SNicolin Chen {
149165bc25b8SMatus Gajdos static const u32 rate[] = { 22050, 32000, 44100, 48000, 88200, 96000, 176400,
14921bfa3eaaSShengjiu Wang 192000, };
1493a2388a49SNicolin Chen struct platform_device *pdev = spdif_priv->pdev;
1494a2388a49SNicolin Chen struct device *dev = &pdev->dev;
1495a2388a49SNicolin Chen u64 savesub = 100000, ret;
1496a2388a49SNicolin Chen struct clk *clk;
1497a2388a49SNicolin Chen int i;
1498a2388a49SNicolin Chen
1499a2388a49SNicolin Chen for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
15005bd998afSViorel Suman clk = spdif_priv->txclk[i];
1501a2388a49SNicolin Chen if (IS_ERR(clk)) {
1502a2388a49SNicolin Chen dev_err(dev, "no rxtx%d clock in devicetree\n", i);
1503a2388a49SNicolin Chen return PTR_ERR(clk);
1504a2388a49SNicolin Chen }
1505a2388a49SNicolin Chen if (!clk_get_rate(clk))
1506a2388a49SNicolin Chen continue;
1507a2388a49SNicolin Chen
15089c6344b3SNicolin Chen ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index,
1509f61b9273SShengjiu Wang fsl_spdif_can_set_clk_rate(spdif_priv, i));
1510a2388a49SNicolin Chen if (savesub == ret)
1511a2388a49SNicolin Chen continue;
1512a2388a49SNicolin Chen
1513a2388a49SNicolin Chen savesub = ret;
1514a2388a49SNicolin Chen spdif_priv->txclk_src[index] = i;
1515a2388a49SNicolin Chen
1516a2388a49SNicolin Chen /* To quick catch a divisor, we allow a 0.1% deviation */
1517a2388a49SNicolin Chen if (savesub < 100)
1518a2388a49SNicolin Chen break;
1519a2388a49SNicolin Chen }
1520a2388a49SNicolin Chen
152168be8ed6STang Bin dev_dbg(dev, "use rxtx%d as tx clock source for %dHz sample rate\n",
1522a2388a49SNicolin Chen spdif_priv->txclk_src[index], rate[index]);
152368be8ed6STang Bin dev_dbg(dev, "use txclk df %d for %dHz sample rate\n",
1524e41a4a79SNicolin Chen spdif_priv->txclk_df[index], rate[index]);
15255bd998afSViorel Suman if (clk_is_match(spdif_priv->txclk[spdif_priv->txclk_src[index]], spdif_priv->sysclk))
152668be8ed6STang Bin dev_dbg(dev, "use sysclk df %d for %dHz sample rate\n",
152727c647bfSNicolin Chen spdif_priv->sysclk_df[index], rate[index]);
152868be8ed6STang Bin dev_dbg(dev, "the best rate for %dHz sample rate is %dHz\n",
1529527cda78SNicolin Chen rate[index], spdif_priv->txrate[index]);
1530a2388a49SNicolin Chen
1531a2388a49SNicolin Chen return 0;
1532a2388a49SNicolin Chen }
1533a2388a49SNicolin Chen
fsl_spdif_probe(struct platform_device * pdev)1534a2388a49SNicolin Chen static int fsl_spdif_probe(struct platform_device *pdev)
1535a2388a49SNicolin Chen {
1536a2388a49SNicolin Chen struct fsl_spdif_priv *spdif_priv;
1537a2388a49SNicolin Chen struct spdif_mixer_control *ctrl;
1538a2388a49SNicolin Chen struct resource *res;
1539a2388a49SNicolin Chen void __iomem *regs;
1540a2388a49SNicolin Chen int irq, ret, i;
15415bd998afSViorel Suman char tmp[16];
1542a2388a49SNicolin Chen
15437c27ba46SFabio Estevam spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL);
1544a2388a49SNicolin Chen if (!spdif_priv)
1545a2388a49SNicolin Chen return -ENOMEM;
1546a2388a49SNicolin Chen
1547a2388a49SNicolin Chen spdif_priv->pdev = pdev;
1548a2388a49SNicolin Chen
1549f61b9273SShengjiu Wang spdif_priv->soc = of_device_get_match_data(&pdev->dev);
1550f61b9273SShengjiu Wang
1551a2388a49SNicolin Chen /* Initialize this copy of the CPU DAI driver structure */
1552a2388a49SNicolin Chen memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai));
15537c27ba46SFabio Estevam spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev);
1554516232e3SShengjiu Wang spdif_priv->cpu_dai_drv.playback.formats =
1555516232e3SShengjiu Wang spdif_priv->soc->tx_formats;
1556a2388a49SNicolin Chen
1557a2388a49SNicolin Chen /* Get the addresses and IRQ */
1558cbb7ea0aSYang Yingliang regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
1559bfd7d1aaSWei Yongjun if (IS_ERR(regs))
1560a2388a49SNicolin Chen return PTR_ERR(regs);
1561a2388a49SNicolin Chen
1562c2562572SShengjiu Wang spdif_priv->regmap = devm_regmap_init_mmio(&pdev->dev, regs, &fsl_spdif_regmap_config);
1563a2388a49SNicolin Chen if (IS_ERR(spdif_priv->regmap)) {
1564a2388a49SNicolin Chen dev_err(&pdev->dev, "regmap init failed\n");
1565a2388a49SNicolin Chen return PTR_ERR(spdif_priv->regmap);
1566a2388a49SNicolin Chen }
1567a2388a49SNicolin Chen
1568516232e3SShengjiu Wang for (i = 0; i < spdif_priv->soc->interrupts; i++) {
1569516232e3SShengjiu Wang irq = platform_get_irq(pdev, i);
15702e8a8adbSTan Zhongjun if (irq < 0)
1571a2388a49SNicolin Chen return irq;
1572a2388a49SNicolin Chen
1573a2388a49SNicolin Chen ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0,
15747c27ba46SFabio Estevam dev_name(&pdev->dev), spdif_priv);
1575a2388a49SNicolin Chen if (ret) {
1576a2388a49SNicolin Chen dev_err(&pdev->dev, "could not claim irq %u\n", irq);
1577a2388a49SNicolin Chen return ret;
1578a2388a49SNicolin Chen }
1579516232e3SShengjiu Wang }
1580a2388a49SNicolin Chen
15815bd998afSViorel Suman for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
15825bd998afSViorel Suman sprintf(tmp, "rxtx%d", i);
15835bd998afSViorel Suman spdif_priv->txclk[i] = devm_clk_get(&pdev->dev, tmp);
15845bd998afSViorel Suman if (IS_ERR(spdif_priv->txclk[i])) {
15855bd998afSViorel Suman dev_err(&pdev->dev, "no rxtx%d clock in devicetree\n", i);
15865bd998afSViorel Suman return PTR_ERR(spdif_priv->txclk[i]);
15875bd998afSViorel Suman }
15885bd998afSViorel Suman }
15895bd998afSViorel Suman
15900b864390SNicolin Chen /* Get system clock for rx clock rate calculation */
15915bd998afSViorel Suman spdif_priv->sysclk = spdif_priv->txclk[5];
15920b864390SNicolin Chen if (IS_ERR(spdif_priv->sysclk)) {
15930b864390SNicolin Chen dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n");
15940b864390SNicolin Chen return PTR_ERR(spdif_priv->sysclk);
15950b864390SNicolin Chen }
15960b864390SNicolin Chen
159708f7336eSNicolin Chen /* Get core clock for data register access via DMA */
159808f7336eSNicolin Chen spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core");
159908f7336eSNicolin Chen if (IS_ERR(spdif_priv->coreclk)) {
160008f7336eSNicolin Chen dev_err(&pdev->dev, "no core clock in devicetree\n");
160108f7336eSNicolin Chen return PTR_ERR(spdif_priv->coreclk);
160208f7336eSNicolin Chen }
160308f7336eSNicolin Chen
16040bc5680aSShengjiu Wang spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba");
16050bc5680aSShengjiu Wang if (IS_ERR(spdif_priv->spbaclk))
16060bc5680aSShengjiu Wang dev_warn(&pdev->dev, "no spba clock in devicetree\n");
16070bc5680aSShengjiu Wang
1608a2388a49SNicolin Chen /* Select clock source for rx/tx clock */
16095bd998afSViorel Suman spdif_priv->rxclk = spdif_priv->txclk[1];
1610a2388a49SNicolin Chen if (IS_ERR(spdif_priv->rxclk)) {
1611a2388a49SNicolin Chen dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n");
1612a2388a49SNicolin Chen return PTR_ERR(spdif_priv->rxclk);
1613a2388a49SNicolin Chen }
1614a2388a49SNicolin Chen spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC;
1615a2388a49SNicolin Chen
161634dcdebeSShengjiu Wang fsl_asoc_get_pll_clocks(&pdev->dev, &spdif_priv->pll8k_clk,
161734dcdebeSShengjiu Wang &spdif_priv->pll11k_clk);
1618a2388a49SNicolin Chen
1619a2388a49SNicolin Chen /* Initial spinlock for control data */
1620a2388a49SNicolin Chen ctrl = &spdif_priv->fsl_spdif_control;
1621a2388a49SNicolin Chen spin_lock_init(&ctrl->ctl_lock);
1622a2388a49SNicolin Chen
1623a2388a49SNicolin Chen /* Init tx channel status default value */
1624f3a30baaSNicolin Chen ctrl->ch_status[0] = IEC958_AES0_CON_NOT_COPYRIGHT |
1625f3a30baaSNicolin Chen IEC958_AES0_CON_EMPHASIS_5015;
1626a2388a49SNicolin Chen ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID;
1627a2388a49SNicolin Chen ctrl->ch_status[2] = 0x00;
1628f3a30baaSNicolin Chen ctrl->ch_status[3] = IEC958_AES3_CON_FS_44100 |
1629f3a30baaSNicolin Chen IEC958_AES3_CON_CLOCK_1000PPM;
1630a2388a49SNicolin Chen
1631a2388a49SNicolin Chen spdif_priv->dpll_locked = false;
1632a2388a49SNicolin Chen
1633516232e3SShengjiu Wang spdif_priv->dma_params_tx.maxburst = spdif_priv->soc->tx_burst;
1634516232e3SShengjiu Wang spdif_priv->dma_params_rx.maxburst = spdif_priv->soc->rx_burst;
1635a2388a49SNicolin Chen spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL;
1636a2388a49SNicolin Chen spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL;
1637a2388a49SNicolin Chen
1638a2388a49SNicolin Chen /* Register with ASoC */
1639a2388a49SNicolin Chen dev_set_drvdata(&pdev->dev, spdif_priv);
16409cb2b379SShengjiu Wang pm_runtime_enable(&pdev->dev);
16419cb2b379SShengjiu Wang regcache_cache_only(spdif_priv->regmap, true);
1642a2388a49SNicolin Chen
1643ee8ccc2eSShengjiu Wang /*
1644ee8ccc2eSShengjiu Wang * Register platform component before registering cpu dai for there
1645ee8ccc2eSShengjiu Wang * is not defer probe for platform component in snd_soc_add_pcm_runtime().
1646ee8ccc2eSShengjiu Wang */
16479b3ff637SSascha Hauer ret = imx_pcm_dma_init(pdev);
1648ee8ccc2eSShengjiu Wang if (ret) {
1649ee8ccc2eSShengjiu Wang dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n");
1650ee8ccc2eSShengjiu Wang goto err_pm_disable;
1651ee8ccc2eSShengjiu Wang }
1652ee8ccc2eSShengjiu Wang
1653256218aeSSachin Kamat ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component,
1654a2388a49SNicolin Chen &spdif_priv->cpu_dai_drv, 1);
1655a2388a49SNicolin Chen if (ret) {
1656a2388a49SNicolin Chen dev_err(&pdev->dev, "failed to register DAI: %d\n", ret);
165728108d71SShengjiu Wang goto err_pm_disable;
1658a2388a49SNicolin Chen }
1659a2388a49SNicolin Chen
1660a2388a49SNicolin Chen return ret;
166128108d71SShengjiu Wang
166228108d71SShengjiu Wang err_pm_disable:
166328108d71SShengjiu Wang pm_runtime_disable(&pdev->dev);
166428108d71SShengjiu Wang return ret;
166528108d71SShengjiu Wang }
166628108d71SShengjiu Wang
fsl_spdif_remove(struct platform_device * pdev)1667c8c0bd47SUwe Kleine-König static void fsl_spdif_remove(struct platform_device *pdev)
166828108d71SShengjiu Wang {
166928108d71SShengjiu Wang pm_runtime_disable(&pdev->dev);
1670a2388a49SNicolin Chen }
1671a2388a49SNicolin Chen
16729cb2b379SShengjiu Wang #ifdef CONFIG_PM
fsl_spdif_runtime_suspend(struct device * dev)16739cb2b379SShengjiu Wang static int fsl_spdif_runtime_suspend(struct device *dev)
1674f9f4fa61SZidan Wang {
1675f9f4fa61SZidan Wang struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
16769cb2b379SShengjiu Wang int i;
1677f9f4fa61SZidan Wang
1678a7a0a2feSShengjiu Wang /* Disable all the interrupts */
1679a7a0a2feSShengjiu Wang regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0);
1680a7a0a2feSShengjiu Wang
1681f9f4fa61SZidan Wang regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC,
1682f9f4fa61SZidan Wang &spdif_priv->regcache_srpc);
1683f9f4fa61SZidan Wang regcache_cache_only(spdif_priv->regmap, true);
16849cb2b379SShengjiu Wang
16855bd998afSViorel Suman for (i = 0; i < STC_TXCLK_SRC_MAX; i++)
16869cb2b379SShengjiu Wang clk_disable_unprepare(spdif_priv->txclk[i]);
16879cb2b379SShengjiu Wang
16889cb2b379SShengjiu Wang if (!IS_ERR(spdif_priv->spbaclk))
16899cb2b379SShengjiu Wang clk_disable_unprepare(spdif_priv->spbaclk);
16909cb2b379SShengjiu Wang clk_disable_unprepare(spdif_priv->coreclk);
1691f9f4fa61SZidan Wang
1692f9f4fa61SZidan Wang return 0;
1693f9f4fa61SZidan Wang }
1694f9f4fa61SZidan Wang
fsl_spdif_runtime_resume(struct device * dev)16959cb2b379SShengjiu Wang static int fsl_spdif_runtime_resume(struct device *dev)
1696f9f4fa61SZidan Wang {
1697f9f4fa61SZidan Wang struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev);
16989cb2b379SShengjiu Wang int ret;
16999cb2b379SShengjiu Wang int i;
17009cb2b379SShengjiu Wang
17019cb2b379SShengjiu Wang ret = clk_prepare_enable(spdif_priv->coreclk);
17029cb2b379SShengjiu Wang if (ret) {
17039cb2b379SShengjiu Wang dev_err(dev, "failed to enable core clock\n");
17049cb2b379SShengjiu Wang return ret;
17059cb2b379SShengjiu Wang }
17069cb2b379SShengjiu Wang
17079cb2b379SShengjiu Wang if (!IS_ERR(spdif_priv->spbaclk)) {
17089cb2b379SShengjiu Wang ret = clk_prepare_enable(spdif_priv->spbaclk);
17099cb2b379SShengjiu Wang if (ret) {
17109cb2b379SShengjiu Wang dev_err(dev, "failed to enable spba clock\n");
17119cb2b379SShengjiu Wang goto disable_core_clk;
17129cb2b379SShengjiu Wang }
17139cb2b379SShengjiu Wang }
17149cb2b379SShengjiu Wang
17155bd998afSViorel Suman for (i = 0; i < STC_TXCLK_SRC_MAX; i++) {
17169cb2b379SShengjiu Wang ret = clk_prepare_enable(spdif_priv->txclk[i]);
17179cb2b379SShengjiu Wang if (ret)
17189cb2b379SShengjiu Wang goto disable_tx_clk;
17199cb2b379SShengjiu Wang }
17209cb2b379SShengjiu Wang
1721f9f4fa61SZidan Wang regcache_cache_only(spdif_priv->regmap, false);
17229cb2b379SShengjiu Wang regcache_mark_dirty(spdif_priv->regmap);
1723f9f4fa61SZidan Wang
1724f9f4fa61SZidan Wang regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC,
1725f9f4fa61SZidan Wang SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK,
1726f9f4fa61SZidan Wang spdif_priv->regcache_srpc);
1727f9f4fa61SZidan Wang
17289cb2b379SShengjiu Wang ret = regcache_sync(spdif_priv->regmap);
17299cb2b379SShengjiu Wang if (ret)
17305bd998afSViorel Suman goto disable_tx_clk;
17319cb2b379SShengjiu Wang
17329cb2b379SShengjiu Wang return 0;
17339cb2b379SShengjiu Wang
17349cb2b379SShengjiu Wang disable_tx_clk:
17359cb2b379SShengjiu Wang for (i--; i >= 0; i--)
17369cb2b379SShengjiu Wang clk_disable_unprepare(spdif_priv->txclk[i]);
17379cb2b379SShengjiu Wang if (!IS_ERR(spdif_priv->spbaclk))
17389cb2b379SShengjiu Wang clk_disable_unprepare(spdif_priv->spbaclk);
17399cb2b379SShengjiu Wang disable_core_clk:
17409cb2b379SShengjiu Wang clk_disable_unprepare(spdif_priv->coreclk);
17419cb2b379SShengjiu Wang
17429cb2b379SShengjiu Wang return ret;
1743f9f4fa61SZidan Wang }
17449cb2b379SShengjiu Wang #endif /* CONFIG_PM */
1745f9f4fa61SZidan Wang
1746f9f4fa61SZidan Wang static const struct dev_pm_ops fsl_spdif_pm = {
17479cb2b379SShengjiu Wang SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
17489cb2b379SShengjiu Wang pm_runtime_force_resume)
17499cb2b379SShengjiu Wang SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume,
17509cb2b379SShengjiu Wang NULL)
1751f9f4fa61SZidan Wang };
1752f9f4fa61SZidan Wang
1753a2388a49SNicolin Chen static const struct of_device_id fsl_spdif_dt_ids[] = {
1754f61b9273SShengjiu Wang { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, },
1755f61b9273SShengjiu Wang { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, },
1756f61b9273SShengjiu Wang { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, },
1757516232e3SShengjiu Wang { .compatible = "fsl,imx8qm-spdif", .data = &fsl_spdif_imx8qm, },
1758604e5178SViorel Suman { .compatible = "fsl,imx8mm-spdif", .data = &fsl_spdif_imx8mm, },
1759a635d66bSShengjiu Wang { .compatible = "fsl,imx8ulp-spdif", .data = &fsl_spdif_imx8ulp, },
1760a2388a49SNicolin Chen {}
1761a2388a49SNicolin Chen };
1762a2388a49SNicolin Chen MODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids);
1763a2388a49SNicolin Chen
1764a2388a49SNicolin Chen static struct platform_driver fsl_spdif_driver = {
1765a2388a49SNicolin Chen .driver = {
1766a2388a49SNicolin Chen .name = "fsl-spdif-dai",
1767a2388a49SNicolin Chen .of_match_table = fsl_spdif_dt_ids,
1768f9f4fa61SZidan Wang .pm = &fsl_spdif_pm,
1769a2388a49SNicolin Chen },
1770a2388a49SNicolin Chen .probe = fsl_spdif_probe,
1771c8c0bd47SUwe Kleine-König .remove_new = fsl_spdif_remove,
1772a2388a49SNicolin Chen };
1773a2388a49SNicolin Chen
1774a2388a49SNicolin Chen module_platform_driver(fsl_spdif_driver);
1775a2388a49SNicolin Chen
1776a2388a49SNicolin Chen MODULE_AUTHOR("Freescale Semiconductor, Inc.");
1777a2388a49SNicolin Chen MODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver");
1778a2388a49SNicolin Chen MODULE_LICENSE("GPL v2");
1779a2388a49SNicolin Chen MODULE_ALIAS("platform:fsl-spdif-dai");
1780