18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Freescale S/PDIF ALSA SoC Digital Audio Interface (DAI) driver 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2013 Freescale Semiconductor, Inc. 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Based on stmp3xxx_spdif_dai.c 88c2ecf20Sopenharmony_ci// Vladimir Barinov <vbarinov@embeddedalley.com> 98c2ecf20Sopenharmony_ci// Copyright 2008 SigmaTel, Inc 108c2ecf20Sopenharmony_ci// Copyright 2008 Embedded Alley Solutions, Inc 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 138c2ecf20Sopenharmony_ci#include <linux/clk.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_address.h> 168c2ecf20Sopenharmony_ci#include <linux/of_device.h> 178c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 188c2ecf20Sopenharmony_ci#include <linux/regmap.h> 198c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <sound/asoundef.h> 228c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 238c2ecf20Sopenharmony_ci#include <sound/soc.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "fsl_spdif.h" 268c2ecf20Sopenharmony_ci#include "imx-pcm.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define FSL_SPDIF_TXFIFO_WML 0x8 298c2ecf20Sopenharmony_ci#define FSL_SPDIF_RXFIFO_WML 0x8 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define INTR_FOR_PLAYBACK (INT_TXFIFO_RESYNC) 328c2ecf20Sopenharmony_ci#define INTR_FOR_CAPTURE (INT_SYM_ERR | INT_BIT_ERR | INT_URX_FUL |\ 338c2ecf20Sopenharmony_ci INT_URX_OV | INT_QRX_FUL | INT_QRX_OV |\ 348c2ecf20Sopenharmony_ci INT_UQ_SYNC | INT_UQ_ERR | INT_RXFIFO_RESYNC |\ 358c2ecf20Sopenharmony_ci INT_LOSS_LOCK | INT_DPLL_LOCKED) 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#define SIE_INTR_FOR(tx) (tx ? INTR_FOR_PLAYBACK : INTR_FOR_CAPTURE) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Index list for the values that has if (DPLL Locked) condition */ 408c2ecf20Sopenharmony_cistatic u8 srpc_dpll_locked[] = { 0x0, 0x1, 0x2, 0x3, 0x4, 0xa, 0xb }; 418c2ecf20Sopenharmony_ci#define SRPC_NODPLL_START1 0x5 428c2ecf20Sopenharmony_ci#define SRPC_NODPLL_START2 0xc 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define DEFAULT_RXCLK_SRC 1 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/** 478c2ecf20Sopenharmony_ci * struct fsl_spdif_soc_data: soc specific data 488c2ecf20Sopenharmony_ci * 498c2ecf20Sopenharmony_ci * @imx: for imx platform 508c2ecf20Sopenharmony_ci * @shared_root_clock: flag of sharing a clock source with others; 518c2ecf20Sopenharmony_ci * so the driver shouldn't set root clock rate 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_cistruct fsl_spdif_soc_data { 548c2ecf20Sopenharmony_ci bool imx; 558c2ecf20Sopenharmony_ci bool shared_root_clock; 568c2ecf20Sopenharmony_ci}; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci/* 598c2ecf20Sopenharmony_ci * SPDIF control structure 608c2ecf20Sopenharmony_ci * Defines channel status, subcode and Q sub 618c2ecf20Sopenharmony_ci */ 628c2ecf20Sopenharmony_cistruct spdif_mixer_control { 638c2ecf20Sopenharmony_ci /* spinlock to access control data */ 648c2ecf20Sopenharmony_ci spinlock_t ctl_lock; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* IEC958 channel tx status bit */ 678c2ecf20Sopenharmony_ci unsigned char ch_status[4]; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* User bits */ 708c2ecf20Sopenharmony_ci unsigned char subcode[2 * SPDIF_UBITS_SIZE]; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci /* Q subcode part of user bits */ 738c2ecf20Sopenharmony_ci unsigned char qsub[2 * SPDIF_QSUB_SIZE]; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci /* Buffer offset for U/Q */ 768c2ecf20Sopenharmony_ci u32 upos; 778c2ecf20Sopenharmony_ci u32 qpos; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci /* Ready buffer index of the two buffers */ 808c2ecf20Sopenharmony_ci u32 ready_buf; 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/** 848c2ecf20Sopenharmony_ci * struct fsl_spdif_priv - Freescale SPDIF private data 858c2ecf20Sopenharmony_ci * @soc: SPDIF soc data 868c2ecf20Sopenharmony_ci * @fsl_spdif_control: SPDIF control data 878c2ecf20Sopenharmony_ci * @cpu_dai_drv: cpu dai driver 888c2ecf20Sopenharmony_ci * @pdev: platform device pointer 898c2ecf20Sopenharmony_ci * @regmap: regmap handler 908c2ecf20Sopenharmony_ci * @dpll_locked: dpll lock flag 918c2ecf20Sopenharmony_ci * @txrate: the best rates for playback 928c2ecf20Sopenharmony_ci * @txclk_df: STC_TXCLK_DF dividers value for playback 938c2ecf20Sopenharmony_ci * @sysclk_df: STC_SYSCLK_DF dividers value for playback 948c2ecf20Sopenharmony_ci * @txclk_src: STC_TXCLK_SRC values for playback 958c2ecf20Sopenharmony_ci * @rxclk_src: SRPC_CLKSRC_SEL values for capture 968c2ecf20Sopenharmony_ci * @txclk: tx clock sources for playback 978c2ecf20Sopenharmony_ci * @rxclk: rx clock sources for capture 988c2ecf20Sopenharmony_ci * @coreclk: core clock for register access via DMA 998c2ecf20Sopenharmony_ci * @sysclk: system clock for rx clock rate measurement 1008c2ecf20Sopenharmony_ci * @spbaclk: SPBA clock (optional, depending on SoC design) 1018c2ecf20Sopenharmony_ci * @dma_params_tx: DMA parameters for transmit channel 1028c2ecf20Sopenharmony_ci * @dma_params_rx: DMA parameters for receive channel 1038c2ecf20Sopenharmony_ci * @regcache_srpc: regcache for SRPC 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistruct fsl_spdif_priv { 1068c2ecf20Sopenharmony_ci const struct fsl_spdif_soc_data *soc; 1078c2ecf20Sopenharmony_ci struct spdif_mixer_control fsl_spdif_control; 1088c2ecf20Sopenharmony_ci struct snd_soc_dai_driver cpu_dai_drv; 1098c2ecf20Sopenharmony_ci struct platform_device *pdev; 1108c2ecf20Sopenharmony_ci struct regmap *regmap; 1118c2ecf20Sopenharmony_ci bool dpll_locked; 1128c2ecf20Sopenharmony_ci u32 txrate[SPDIF_TXRATE_MAX]; 1138c2ecf20Sopenharmony_ci u8 txclk_df[SPDIF_TXRATE_MAX]; 1148c2ecf20Sopenharmony_ci u16 sysclk_df[SPDIF_TXRATE_MAX]; 1158c2ecf20Sopenharmony_ci u8 txclk_src[SPDIF_TXRATE_MAX]; 1168c2ecf20Sopenharmony_ci u8 rxclk_src; 1178c2ecf20Sopenharmony_ci struct clk *txclk[SPDIF_TXRATE_MAX]; 1188c2ecf20Sopenharmony_ci struct clk *rxclk; 1198c2ecf20Sopenharmony_ci struct clk *coreclk; 1208c2ecf20Sopenharmony_ci struct clk *sysclk; 1218c2ecf20Sopenharmony_ci struct clk *spbaclk; 1228c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_params_tx; 1238c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_params_rx; 1248c2ecf20Sopenharmony_ci /* regcache for SRPC */ 1258c2ecf20Sopenharmony_ci u32 regcache_srpc; 1268c2ecf20Sopenharmony_ci}; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_cistatic struct fsl_spdif_soc_data fsl_spdif_vf610 = { 1298c2ecf20Sopenharmony_ci .imx = false, 1308c2ecf20Sopenharmony_ci .shared_root_clock = false, 1318c2ecf20Sopenharmony_ci}; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_cistatic struct fsl_spdif_soc_data fsl_spdif_imx35 = { 1348c2ecf20Sopenharmony_ci .imx = true, 1358c2ecf20Sopenharmony_ci .shared_root_clock = false, 1368c2ecf20Sopenharmony_ci}; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_cistatic struct fsl_spdif_soc_data fsl_spdif_imx6sx = { 1398c2ecf20Sopenharmony_ci .imx = true, 1408c2ecf20Sopenharmony_ci .shared_root_clock = true, 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci/* Check if clk is a root clock that does not share clock source with others */ 1448c2ecf20Sopenharmony_cistatic inline bool fsl_spdif_can_set_clk_rate(struct fsl_spdif_priv *spdif, int clk) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci return (clk == STC_TXCLK_SPDIF_ROOT) && !spdif->soc->shared_root_clock; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* DPLL locked and lock loss interrupt handler */ 1508c2ecf20Sopenharmony_cistatic void spdif_irq_dpll_lock(struct fsl_spdif_priv *spdif_priv) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 1538c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 1548c2ecf20Sopenharmony_ci u32 locked; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRPC, &locked); 1578c2ecf20Sopenharmony_ci locked &= SRPC_DPLL_LOCKED; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Rx dpll %s \n", 1608c2ecf20Sopenharmony_ci locked ? "locked" : "loss lock"); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci spdif_priv->dpll_locked = locked ? true : false; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Receiver found illegal symbol interrupt handler */ 1668c2ecf20Sopenharmony_cistatic void spdif_irq_sym_error(struct fsl_spdif_priv *spdif_priv) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 1698c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: receiver found illegal symbol\n"); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* Clear illegal symbol if DPLL unlocked since no audio stream */ 1748c2ecf20Sopenharmony_ci if (!spdif_priv->dpll_locked) 1758c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SIE, INT_SYM_ERR, 0); 1768c2ecf20Sopenharmony_ci} 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci/* U/Q Channel receive register full */ 1798c2ecf20Sopenharmony_cistatic void spdif_irq_uqrx_full(struct fsl_spdif_priv *spdif_priv, char name) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 1828c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 1838c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 1848c2ecf20Sopenharmony_ci u32 *pos, size, val, reg; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci switch (name) { 1878c2ecf20Sopenharmony_ci case 'U': 1888c2ecf20Sopenharmony_ci pos = &ctrl->upos; 1898c2ecf20Sopenharmony_ci size = SPDIF_UBITS_SIZE; 1908c2ecf20Sopenharmony_ci reg = REG_SPDIF_SRU; 1918c2ecf20Sopenharmony_ci break; 1928c2ecf20Sopenharmony_ci case 'Q': 1938c2ecf20Sopenharmony_ci pos = &ctrl->qpos; 1948c2ecf20Sopenharmony_ci size = SPDIF_QSUB_SIZE; 1958c2ecf20Sopenharmony_ci reg = REG_SPDIF_SRQ; 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci default: 1988c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unsupported channel name\n"); 1998c2ecf20Sopenharmony_ci return; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: %c Channel receive register full\n", name); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci if (*pos >= size * 2) { 2058c2ecf20Sopenharmony_ci *pos = 0; 2068c2ecf20Sopenharmony_ci } else if (unlikely((*pos % size) + 3 > size)) { 2078c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "User bit receive buffer overflow\n"); 2088c2ecf20Sopenharmony_ci return; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci regmap_read(regmap, reg, &val); 2128c2ecf20Sopenharmony_ci ctrl->subcode[*pos++] = val >> 16; 2138c2ecf20Sopenharmony_ci ctrl->subcode[*pos++] = val >> 8; 2148c2ecf20Sopenharmony_ci ctrl->subcode[*pos++] = val; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci/* U/Q Channel sync found */ 2188c2ecf20Sopenharmony_cistatic void spdif_irq_uq_sync(struct fsl_spdif_priv *spdif_priv) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 2218c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: U/Q Channel sync found\n"); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci /* U/Q buffer reset */ 2268c2ecf20Sopenharmony_ci if (ctrl->qpos == 0) 2278c2ecf20Sopenharmony_ci return; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Set ready to this buffer */ 2308c2ecf20Sopenharmony_ci ctrl->ready_buf = (ctrl->qpos - 1) / SPDIF_QSUB_SIZE + 1; 2318c2ecf20Sopenharmony_ci} 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci/* U/Q Channel framing error */ 2348c2ecf20Sopenharmony_cistatic void spdif_irq_uq_err(struct fsl_spdif_priv *spdif_priv) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 2378c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 2388c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 2398c2ecf20Sopenharmony_ci u32 val; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: U/Q Channel framing error\n"); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci /* Read U/Q data to clear the irq and do buffer reset */ 2448c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRU, &val); 2458c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRQ, &val); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci /* Drop this U/Q buffer */ 2488c2ecf20Sopenharmony_ci ctrl->ready_buf = 0; 2498c2ecf20Sopenharmony_ci ctrl->upos = 0; 2508c2ecf20Sopenharmony_ci ctrl->qpos = 0; 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* Get spdif interrupt status and clear the interrupt */ 2548c2ecf20Sopenharmony_cistatic u32 spdif_intr_status_clear(struct fsl_spdif_priv *spdif_priv) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 2578c2ecf20Sopenharmony_ci u32 val, val2; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SIS, &val); 2608c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SIE, &val2); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_SIC, val & val2); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci return val; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_cistatic irqreturn_t spdif_isr(int irq, void *devid) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = (struct fsl_spdif_priv *)devid; 2708c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 2718c2ecf20Sopenharmony_ci u32 sis; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci sis = spdif_intr_status_clear(spdif_priv); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci if (sis & INT_DPLL_LOCKED) 2768c2ecf20Sopenharmony_ci spdif_irq_dpll_lock(spdif_priv); 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci if (sis & INT_TXFIFO_UNOV) 2798c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Tx FIFO under/overrun\n"); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (sis & INT_TXFIFO_RESYNC) 2828c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Tx FIFO resync\n"); 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci if (sis & INT_CNEW) 2858c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: cstatus new\n"); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (sis & INT_VAL_NOGOOD) 2888c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: validity flag no good\n"); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci if (sis & INT_SYM_ERR) 2918c2ecf20Sopenharmony_ci spdif_irq_sym_error(spdif_priv); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (sis & INT_BIT_ERR) 2948c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: receiver found parity bit error\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci if (sis & INT_URX_FUL) 2978c2ecf20Sopenharmony_ci spdif_irq_uqrx_full(spdif_priv, 'U'); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci if (sis & INT_URX_OV) 3008c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: U Channel receive register overrun\n"); 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci if (sis & INT_QRX_FUL) 3038c2ecf20Sopenharmony_ci spdif_irq_uqrx_full(spdif_priv, 'Q'); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci if (sis & INT_QRX_OV) 3068c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Q Channel receive register overrun\n"); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (sis & INT_UQ_SYNC) 3098c2ecf20Sopenharmony_ci spdif_irq_uq_sync(spdif_priv); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (sis & INT_UQ_ERR) 3128c2ecf20Sopenharmony_ci spdif_irq_uq_err(spdif_priv); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (sis & INT_RXFIFO_UNOV) 3158c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Rx FIFO under/overrun\n"); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (sis & INT_RXFIFO_RESYNC) 3188c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Rx FIFO resync\n"); 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (sis & INT_LOSS_LOCK) 3218c2ecf20Sopenharmony_ci spdif_irq_dpll_lock(spdif_priv); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* FIXME: Write Tx FIFO to clear TxEm */ 3248c2ecf20Sopenharmony_ci if (sis & INT_TX_EM) 3258c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Tx FIFO empty\n"); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* FIXME: Read Rx FIFO to clear RxFIFOFul */ 3288c2ecf20Sopenharmony_ci if (sis & INT_RXFIFO_FUL) 3298c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "isr: Rx FIFO full\n"); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3328c2ecf20Sopenharmony_ci} 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_cistatic int spdif_softreset(struct fsl_spdif_priv *spdif_priv) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 3378c2ecf20Sopenharmony_ci u32 val, cycle = 1000; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci regcache_cache_bypass(regmap, true); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_SCR, SCR_SOFT_RESET); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * RESET bit would be cleared after finishing its reset procedure, 3458c2ecf20Sopenharmony_ci * which typically lasts 8 cycles. 1000 cycles will keep it safe. 3468c2ecf20Sopenharmony_ci */ 3478c2ecf20Sopenharmony_ci do { 3488c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SCR, &val); 3498c2ecf20Sopenharmony_ci } while ((val & SCR_SOFT_RESET) && cycle--); 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci regcache_cache_bypass(regmap, false); 3528c2ecf20Sopenharmony_ci regcache_mark_dirty(regmap); 3538c2ecf20Sopenharmony_ci regcache_sync(regmap); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci if (cycle) 3568c2ecf20Sopenharmony_ci return 0; 3578c2ecf20Sopenharmony_ci else 3588c2ecf20Sopenharmony_ci return -EBUSY; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_cistatic void spdif_set_cstatus(struct spdif_mixer_control *ctrl, 3628c2ecf20Sopenharmony_ci u8 mask, u8 cstatus) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci ctrl->ch_status[3] &= ~mask; 3658c2ecf20Sopenharmony_ci ctrl->ch_status[3] |= cstatus & mask; 3668c2ecf20Sopenharmony_ci} 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic void spdif_write_channel_status(struct fsl_spdif_priv *spdif_priv) 3698c2ecf20Sopenharmony_ci{ 3708c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 3718c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 3728c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 3738c2ecf20Sopenharmony_ci u32 ch_status; 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci ch_status = (bitrev8(ctrl->ch_status[0]) << 16) | 3768c2ecf20Sopenharmony_ci (bitrev8(ctrl->ch_status[1]) << 8) | 3778c2ecf20Sopenharmony_ci bitrev8(ctrl->ch_status[2]); 3788c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_STCSCH, ch_status); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "STCSCH: 0x%06x\n", ch_status); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci ch_status = bitrev8(ctrl->ch_status[3]) << 16; 3838c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_STCSCL, ch_status); 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "STCSCL: 0x%06x\n", ch_status); 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_ci 3888c2ecf20Sopenharmony_ci/* Set SPDIF PhaseConfig register for rx clock */ 3898c2ecf20Sopenharmony_cistatic int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv, 3908c2ecf20Sopenharmony_ci enum spdif_gainsel gainsel, int dpll_locked) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 3938c2ecf20Sopenharmony_ci u8 clksrc = spdif_priv->rxclk_src; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (clksrc >= SRPC_CLKSRC_MAX || gainsel >= GAINSEL_MULTI_MAX) 3968c2ecf20Sopenharmony_ci return -EINVAL; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SRPC, 3998c2ecf20Sopenharmony_ci SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, 4008c2ecf20Sopenharmony_ci SRPC_CLKSRC_SEL_SET(clksrc) | SRPC_GAINSEL_SET(gainsel)); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic int spdif_set_sample_rate(struct snd_pcm_substream *substream, 4068c2ecf20Sopenharmony_ci int sample_rate) 4078c2ecf20Sopenharmony_ci{ 4088c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 4098c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 4108c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 4118c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 4128c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 4138c2ecf20Sopenharmony_ci unsigned long csfs = 0; 4148c2ecf20Sopenharmony_ci u32 stc, mask, rate; 4158c2ecf20Sopenharmony_ci u16 sysclk_df; 4168c2ecf20Sopenharmony_ci u8 clk, txclk_df; 4178c2ecf20Sopenharmony_ci int ret; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci switch (sample_rate) { 4208c2ecf20Sopenharmony_ci case 32000: 4218c2ecf20Sopenharmony_ci rate = SPDIF_TXRATE_32000; 4228c2ecf20Sopenharmony_ci csfs = IEC958_AES3_CON_FS_32000; 4238c2ecf20Sopenharmony_ci break; 4248c2ecf20Sopenharmony_ci case 44100: 4258c2ecf20Sopenharmony_ci rate = SPDIF_TXRATE_44100; 4268c2ecf20Sopenharmony_ci csfs = IEC958_AES3_CON_FS_44100; 4278c2ecf20Sopenharmony_ci break; 4288c2ecf20Sopenharmony_ci case 48000: 4298c2ecf20Sopenharmony_ci rate = SPDIF_TXRATE_48000; 4308c2ecf20Sopenharmony_ci csfs = IEC958_AES3_CON_FS_48000; 4318c2ecf20Sopenharmony_ci break; 4328c2ecf20Sopenharmony_ci case 96000: 4338c2ecf20Sopenharmony_ci rate = SPDIF_TXRATE_96000; 4348c2ecf20Sopenharmony_ci csfs = IEC958_AES3_CON_FS_96000; 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci case 192000: 4378c2ecf20Sopenharmony_ci rate = SPDIF_TXRATE_192000; 4388c2ecf20Sopenharmony_ci csfs = IEC958_AES3_CON_FS_192000; 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci default: 4418c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "unsupported sample rate %d\n", sample_rate); 4428c2ecf20Sopenharmony_ci return -EINVAL; 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci clk = spdif_priv->txclk_src[rate]; 4468c2ecf20Sopenharmony_ci if (clk >= STC_TXCLK_SRC_MAX) { 4478c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "tx clock source is out of range\n"); 4488c2ecf20Sopenharmony_ci return -EINVAL; 4498c2ecf20Sopenharmony_ci } 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci txclk_df = spdif_priv->txclk_df[rate]; 4528c2ecf20Sopenharmony_ci if (txclk_df == 0) { 4538c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "the txclk_df can't be zero\n"); 4548c2ecf20Sopenharmony_ci return -EINVAL; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci sysclk_df = spdif_priv->sysclk_df[rate]; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (!fsl_spdif_can_set_clk_rate(spdif_priv, clk)) 4608c2ecf20Sopenharmony_ci goto clk_set_bypass; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* The S/PDIF block needs a clock of 64 * fs * txclk_df */ 4638c2ecf20Sopenharmony_ci ret = clk_set_rate(spdif_priv->txclk[rate], 4648c2ecf20Sopenharmony_ci 64 * sample_rate * txclk_df); 4658c2ecf20Sopenharmony_ci if (ret) { 4668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to set tx clock rate\n"); 4678c2ecf20Sopenharmony_ci return ret; 4688c2ecf20Sopenharmony_ci } 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ciclk_set_bypass: 4718c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "expected clock rate = %d\n", 4728c2ecf20Sopenharmony_ci (64 * sample_rate * txclk_df * sysclk_df)); 4738c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "actual clock rate = %ld\n", 4748c2ecf20Sopenharmony_ci clk_get_rate(spdif_priv->txclk[rate])); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci /* set fs field in consumer channel status */ 4778c2ecf20Sopenharmony_ci spdif_set_cstatus(ctrl, IEC958_AES3_CON_FS, csfs); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci /* select clock source and divisor */ 4808c2ecf20Sopenharmony_ci stc = STC_TXCLK_ALL_EN | STC_TXCLK_SRC_SET(clk) | 4818c2ecf20Sopenharmony_ci STC_TXCLK_DF(txclk_df) | STC_SYSCLK_DF(sysclk_df); 4828c2ecf20Sopenharmony_ci mask = STC_TXCLK_ALL_EN_MASK | STC_TXCLK_SRC_MASK | 4838c2ecf20Sopenharmony_ci STC_TXCLK_DF_MASK | STC_SYSCLK_DF_MASK; 4848c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_STC, mask, stc); 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "set sample rate to %dHz for %dHz playback\n", 4878c2ecf20Sopenharmony_ci spdif_priv->txrate[rate], sample_rate); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci return 0; 4908c2ecf20Sopenharmony_ci} 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_cistatic int fsl_spdif_startup(struct snd_pcm_substream *substream, 4938c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 4948c2ecf20Sopenharmony_ci{ 4958c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 4968c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 4978c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 4988c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 4998c2ecf20Sopenharmony_ci u32 scr, mask; 5008c2ecf20Sopenharmony_ci int ret; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Reset module and interrupts only for first initialization */ 5038c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(cpu_dai)) { 5048c2ecf20Sopenharmony_ci ret = spdif_softreset(spdif_priv); 5058c2ecf20Sopenharmony_ci if (ret) { 5068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to soft reset\n"); 5078c2ecf20Sopenharmony_ci return ret; 5088c2ecf20Sopenharmony_ci } 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci /* Disable all the interrupts */ 5118c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SIE, 0xffffff, 0); 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5158c2ecf20Sopenharmony_ci scr = SCR_TXFIFO_AUTOSYNC | SCR_TXFIFO_CTRL_NORMAL | 5168c2ecf20Sopenharmony_ci SCR_TXSEL_NORMAL | SCR_USRC_SEL_CHIP | 5178c2ecf20Sopenharmony_ci SCR_TXFIFO_FSEL_IF8; 5188c2ecf20Sopenharmony_ci mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | 5198c2ecf20Sopenharmony_ci SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | 5208c2ecf20Sopenharmony_ci SCR_TXFIFO_FSEL_MASK; 5218c2ecf20Sopenharmony_ci } else { 5228c2ecf20Sopenharmony_ci scr = SCR_RXFIFO_FSEL_IF8 | SCR_RXFIFO_AUTOSYNC; 5238c2ecf20Sopenharmony_ci mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| 5248c2ecf20Sopenharmony_ci SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci /* Power up SPDIF module */ 5298c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_LOW_POWER, 0); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci return 0; 5328c2ecf20Sopenharmony_ci} 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_cistatic void fsl_spdif_shutdown(struct snd_pcm_substream *substream, 5358c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 5388c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 5398c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 5408c2ecf20Sopenharmony_ci u32 scr, mask; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5438c2ecf20Sopenharmony_ci scr = 0; 5448c2ecf20Sopenharmony_ci mask = SCR_TXFIFO_AUTOSYNC_MASK | SCR_TXFIFO_CTRL_MASK | 5458c2ecf20Sopenharmony_ci SCR_TXSEL_MASK | SCR_USRC_SEL_MASK | 5468c2ecf20Sopenharmony_ci SCR_TXFIFO_FSEL_MASK; 5478c2ecf20Sopenharmony_ci /* Disable TX clock */ 5488c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_STC, STC_TXCLK_ALL_EN_MASK, 0); 5498c2ecf20Sopenharmony_ci } else { 5508c2ecf20Sopenharmony_ci scr = SCR_RXFIFO_OFF | SCR_RXFIFO_CTL_ZERO; 5518c2ecf20Sopenharmony_ci mask = SCR_RXFIFO_FSEL_MASK | SCR_RXFIFO_AUTOSYNC_MASK| 5528c2ecf20Sopenharmony_ci SCR_RXFIFO_CTL_MASK | SCR_RXFIFO_OFF_MASK; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, mask, scr); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Power down SPDIF module only if tx&rx are both inactive */ 5578c2ecf20Sopenharmony_ci if (!snd_soc_dai_active(cpu_dai)) { 5588c2ecf20Sopenharmony_ci spdif_intr_status_clear(spdif_priv); 5598c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, 5608c2ecf20Sopenharmony_ci SCR_LOW_POWER, SCR_LOW_POWER); 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_cistatic int fsl_spdif_hw_params(struct snd_pcm_substream *substream, 5658c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 5668c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 5698c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 5708c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 5718c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 5728c2ecf20Sopenharmony_ci u32 sample_rate = params_rate(params); 5738c2ecf20Sopenharmony_ci int ret = 0; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 5768c2ecf20Sopenharmony_ci ret = spdif_set_sample_rate(substream, sample_rate); 5778c2ecf20Sopenharmony_ci if (ret) { 5788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s: set sample rate failed: %d\n", 5798c2ecf20Sopenharmony_ci __func__, sample_rate); 5808c2ecf20Sopenharmony_ci return ret; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci spdif_set_cstatus(ctrl, IEC958_AES3_CON_CLOCK, 5838c2ecf20Sopenharmony_ci IEC958_AES3_CON_CLOCK_1000PPM); 5848c2ecf20Sopenharmony_ci spdif_write_channel_status(spdif_priv); 5858c2ecf20Sopenharmony_ci } else { 5868c2ecf20Sopenharmony_ci /* Setup rx clock source */ 5878c2ecf20Sopenharmony_ci ret = spdif_set_rx_clksrc(spdif_priv, SPDIF_DEFAULT_GAINSEL, 1); 5888c2ecf20Sopenharmony_ci } 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_cistatic int fsl_spdif_trigger(struct snd_pcm_substream *substream, 5948c2ecf20Sopenharmony_ci int cmd, struct snd_soc_dai *dai) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); 5978c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(asoc_rtd_to_cpu(rtd, 0)); 5988c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 5998c2ecf20Sopenharmony_ci bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; 6008c2ecf20Sopenharmony_ci u32 intr = SIE_INTR_FOR(tx); 6018c2ecf20Sopenharmony_ci u32 dmaen = SCR_DMA_xX_EN(tx); 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci switch (cmd) { 6048c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 6058c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 6068c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 6078c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SIE, intr, intr); 6088c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, dmaen); 6098c2ecf20Sopenharmony_ci break; 6108c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 6118c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 6128c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 6138c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, dmaen, 0); 6148c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SIE, intr, 0); 6158c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_STL, 0x0); 6168c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_STR, 0x0); 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci default: 6198c2ecf20Sopenharmony_ci return -EINVAL; 6208c2ecf20Sopenharmony_ci } 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci return 0; 6238c2ecf20Sopenharmony_ci} 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops fsl_spdif_dai_ops = { 6268c2ecf20Sopenharmony_ci .startup = fsl_spdif_startup, 6278c2ecf20Sopenharmony_ci .hw_params = fsl_spdif_hw_params, 6288c2ecf20Sopenharmony_ci .trigger = fsl_spdif_trigger, 6298c2ecf20Sopenharmony_ci .shutdown = fsl_spdif_shutdown, 6308c2ecf20Sopenharmony_ci}; 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci/* 6348c2ecf20Sopenharmony_ci * FSL SPDIF IEC958 controller(mixer) functions 6358c2ecf20Sopenharmony_ci * 6368c2ecf20Sopenharmony_ci * Channel status get/put control 6378c2ecf20Sopenharmony_ci * User bit value get/put control 6388c2ecf20Sopenharmony_ci * Valid bit value get control 6398c2ecf20Sopenharmony_ci * DPLL lock status get control 6408c2ecf20Sopenharmony_ci * User bit sync mode selection control 6418c2ecf20Sopenharmony_ci */ 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int fsl_spdif_info(struct snd_kcontrol *kcontrol, 6448c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 6478c2ecf20Sopenharmony_ci uinfo->count = 1; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci return 0; 6508c2ecf20Sopenharmony_ci} 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_cistatic int fsl_spdif_pb_get(struct snd_kcontrol *kcontrol, 6538c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 6548c2ecf20Sopenharmony_ci{ 6558c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 6568c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 6578c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci uvalue->value.iec958.status[0] = ctrl->ch_status[0]; 6608c2ecf20Sopenharmony_ci uvalue->value.iec958.status[1] = ctrl->ch_status[1]; 6618c2ecf20Sopenharmony_ci uvalue->value.iec958.status[2] = ctrl->ch_status[2]; 6628c2ecf20Sopenharmony_ci uvalue->value.iec958.status[3] = ctrl->ch_status[3]; 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci return 0; 6658c2ecf20Sopenharmony_ci} 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic int fsl_spdif_pb_put(struct snd_kcontrol *kcontrol, 6688c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 6718c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 6728c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci ctrl->ch_status[0] = uvalue->value.iec958.status[0]; 6758c2ecf20Sopenharmony_ci ctrl->ch_status[1] = uvalue->value.iec958.status[1]; 6768c2ecf20Sopenharmony_ci ctrl->ch_status[2] = uvalue->value.iec958.status[2]; 6778c2ecf20Sopenharmony_ci ctrl->ch_status[3] = uvalue->value.iec958.status[3]; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci spdif_write_channel_status(spdif_priv); 6808c2ecf20Sopenharmony_ci 6818c2ecf20Sopenharmony_ci return 0; 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci/* Get channel status from SPDIF_RX_CCHAN register */ 6858c2ecf20Sopenharmony_cistatic int fsl_spdif_capture_get(struct snd_kcontrol *kcontrol, 6868c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 6878c2ecf20Sopenharmony_ci{ 6888c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 6898c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 6908c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 6918c2ecf20Sopenharmony_ci u32 cstatus, val; 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SIS, &val); 6948c2ecf20Sopenharmony_ci if (!(val & INT_CNEW)) 6958c2ecf20Sopenharmony_ci return -EAGAIN; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRCSH, &cstatus); 6988c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = (cstatus >> 16) & 0xFF; 6998c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = (cstatus >> 8) & 0xFF; 7008c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = cstatus & 0xFF; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRCSL, &cstatus); 7038c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = (cstatus >> 16) & 0xFF; 7048c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[4] = (cstatus >> 8) & 0xFF; 7058c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[5] = cstatus & 0xFF; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci /* Clear intr */ 7088c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_SIC, INT_CNEW); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci return 0; 7118c2ecf20Sopenharmony_ci} 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci/* 7148c2ecf20Sopenharmony_ci * Get User bits (subcode) from chip value which readed out 7158c2ecf20Sopenharmony_ci * in UChannel register. 7168c2ecf20Sopenharmony_ci */ 7178c2ecf20Sopenharmony_cistatic int fsl_spdif_subcode_get(struct snd_kcontrol *kcontrol, 7188c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7198c2ecf20Sopenharmony_ci{ 7208c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 7218c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 7228c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 7238c2ecf20Sopenharmony_ci unsigned long flags; 7248c2ecf20Sopenharmony_ci int ret = -EAGAIN; 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctrl->ctl_lock, flags); 7278c2ecf20Sopenharmony_ci if (ctrl->ready_buf) { 7288c2ecf20Sopenharmony_ci int idx = (ctrl->ready_buf - 1) * SPDIF_UBITS_SIZE; 7298c2ecf20Sopenharmony_ci memcpy(&ucontrol->value.iec958.subcode[0], 7308c2ecf20Sopenharmony_ci &ctrl->subcode[idx], SPDIF_UBITS_SIZE); 7318c2ecf20Sopenharmony_ci ret = 0; 7328c2ecf20Sopenharmony_ci } 7338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctrl->ctl_lock, flags); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_ci return ret; 7368c2ecf20Sopenharmony_ci} 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci/* Q-subcode information. The byte size is SPDIF_UBITS_SIZE/8 */ 7398c2ecf20Sopenharmony_cistatic int fsl_spdif_qinfo(struct snd_kcontrol *kcontrol, 7408c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 7418c2ecf20Sopenharmony_ci{ 7428c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; 7438c2ecf20Sopenharmony_ci uinfo->count = SPDIF_QSUB_SIZE; 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci return 0; 7468c2ecf20Sopenharmony_ci} 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci/* Get Q subcode from chip value which readed out in QChannel register */ 7498c2ecf20Sopenharmony_cistatic int fsl_spdif_qget(struct snd_kcontrol *kcontrol, 7508c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7518c2ecf20Sopenharmony_ci{ 7528c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 7538c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 7548c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl = &spdif_priv->fsl_spdif_control; 7558c2ecf20Sopenharmony_ci unsigned long flags; 7568c2ecf20Sopenharmony_ci int ret = -EAGAIN; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci spin_lock_irqsave(&ctrl->ctl_lock, flags); 7598c2ecf20Sopenharmony_ci if (ctrl->ready_buf) { 7608c2ecf20Sopenharmony_ci int idx = (ctrl->ready_buf - 1) * SPDIF_QSUB_SIZE; 7618c2ecf20Sopenharmony_ci memcpy(&ucontrol->value.bytes.data[0], 7628c2ecf20Sopenharmony_ci &ctrl->qsub[idx], SPDIF_QSUB_SIZE); 7638c2ecf20Sopenharmony_ci ret = 0; 7648c2ecf20Sopenharmony_ci } 7658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ctrl->ctl_lock, flags); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci return ret; 7688c2ecf20Sopenharmony_ci} 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci/* Valid bit information */ 7718c2ecf20Sopenharmony_cistatic int fsl_spdif_vbit_info(struct snd_kcontrol *kcontrol, 7728c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 7738c2ecf20Sopenharmony_ci{ 7748c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 7758c2ecf20Sopenharmony_ci uinfo->count = 1; 7768c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 7778c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1; 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return 0; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci/* Get valid good bit from interrupt status register */ 7838c2ecf20Sopenharmony_cistatic int fsl_spdif_rx_vbit_get(struct snd_kcontrol *kcontrol, 7848c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7858c2ecf20Sopenharmony_ci{ 7868c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 7878c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 7888c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 7898c2ecf20Sopenharmony_ci u32 val; 7908c2ecf20Sopenharmony_ci 7918c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SIS, &val); 7928c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (val & INT_VAL_NOGOOD) != 0; 7938c2ecf20Sopenharmony_ci regmap_write(regmap, REG_SPDIF_SIC, INT_VAL_NOGOOD); 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci return 0; 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_cistatic int fsl_spdif_tx_vbit_get(struct snd_kcontrol *kcontrol, 7998c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8008c2ecf20Sopenharmony_ci{ 8018c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 8028c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 8038c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 8048c2ecf20Sopenharmony_ci u32 val; 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SCR, &val); 8078c2ecf20Sopenharmony_ci val = (val & SCR_VAL_MASK) >> SCR_VAL_OFFSET; 8088c2ecf20Sopenharmony_ci val = 1 - val; 8098c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = val; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return 0; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic int fsl_spdif_tx_vbit_put(struct snd_kcontrol *kcontrol, 8158c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 8188c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 8198c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 8208c2ecf20Sopenharmony_ci u32 val = (1 - ucontrol->value.integer.value[0]) << SCR_VAL_OFFSET; 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SCR, SCR_VAL_MASK, val); 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci return 0; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci/* DPLL lock information */ 8288c2ecf20Sopenharmony_cistatic int fsl_spdif_rxrate_info(struct snd_kcontrol *kcontrol, 8298c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 8328c2ecf20Sopenharmony_ci uinfo->count = 1; 8338c2ecf20Sopenharmony_ci uinfo->value.integer.min = 16000; 8348c2ecf20Sopenharmony_ci uinfo->value.integer.max = 96000; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci return 0; 8378c2ecf20Sopenharmony_ci} 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_cistatic u32 gainsel_multi[GAINSEL_MULTI_MAX] = { 8408c2ecf20Sopenharmony_ci 24, 16, 12, 8, 6, 4, 3, 8418c2ecf20Sopenharmony_ci}; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci/* Get RX data clock rate given the SPDIF bus_clk */ 8448c2ecf20Sopenharmony_cistatic int spdif_get_rxclk_rate(struct fsl_spdif_priv *spdif_priv, 8458c2ecf20Sopenharmony_ci enum spdif_gainsel gainsel) 8468c2ecf20Sopenharmony_ci{ 8478c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 8488c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 8498c2ecf20Sopenharmony_ci u64 tmpval64, busclk_freq = 0; 8508c2ecf20Sopenharmony_ci u32 freqmeas, phaseconf; 8518c2ecf20Sopenharmony_ci u8 clksrc; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRFM, &freqmeas); 8548c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRPC, &phaseconf); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci clksrc = (phaseconf >> SRPC_CLKSRC_SEL_OFFSET) & 0xf; 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci /* Get bus clock from system */ 8598c2ecf20Sopenharmony_ci if (srpc_dpll_locked[clksrc] && (phaseconf & SRPC_DPLL_LOCKED)) 8608c2ecf20Sopenharmony_ci busclk_freq = clk_get_rate(spdif_priv->sysclk); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci /* FreqMeas_CLK = (BUS_CLK * FreqMeas) / 2 ^ 10 / GAINSEL / 128 */ 8638c2ecf20Sopenharmony_ci tmpval64 = (u64) busclk_freq * freqmeas; 8648c2ecf20Sopenharmony_ci do_div(tmpval64, gainsel_multi[gainsel] * 1024); 8658c2ecf20Sopenharmony_ci do_div(tmpval64, 128 * 1024); 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "FreqMeas: %d\n", freqmeas); 8688c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "BusclkFreq: %lld\n", busclk_freq); 8698c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "RxRate: %lld\n", tmpval64); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return (int)tmpval64; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/* 8758c2ecf20Sopenharmony_ci * Get DPLL lock or not info from stable interrupt status register. 8768c2ecf20Sopenharmony_ci * User application must use this control to get locked, 8778c2ecf20Sopenharmony_ci * then can do next PCM operation 8788c2ecf20Sopenharmony_ci */ 8798c2ecf20Sopenharmony_cistatic int fsl_spdif_rxrate_get(struct snd_kcontrol *kcontrol, 8808c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 8818c2ecf20Sopenharmony_ci{ 8828c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 8838c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 8848c2ecf20Sopenharmony_ci int rate = 0; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (spdif_priv->dpll_locked) 8878c2ecf20Sopenharmony_ci rate = spdif_get_rxclk_rate(spdif_priv, SPDIF_DEFAULT_GAINSEL); 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = rate; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci return 0; 8928c2ecf20Sopenharmony_ci} 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_ci/* User bit sync mode info */ 8958c2ecf20Sopenharmony_cistatic int fsl_spdif_usync_info(struct snd_kcontrol *kcontrol, 8968c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 8978c2ecf20Sopenharmony_ci{ 8988c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 8998c2ecf20Sopenharmony_ci uinfo->count = 1; 9008c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 9018c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci return 0; 9048c2ecf20Sopenharmony_ci} 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci/* 9078c2ecf20Sopenharmony_ci * User bit sync mode: 9088c2ecf20Sopenharmony_ci * 1 CD User channel subcode 9098c2ecf20Sopenharmony_ci * 0 Non-CD data 9108c2ecf20Sopenharmony_ci */ 9118c2ecf20Sopenharmony_cistatic int fsl_spdif_usync_get(struct snd_kcontrol *kcontrol, 9128c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9138c2ecf20Sopenharmony_ci{ 9148c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 9158c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 9168c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 9178c2ecf20Sopenharmony_ci u32 val; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci regmap_read(regmap, REG_SPDIF_SRCD, &val); 9208c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = (val & SRCD_CD_USER) != 0; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci return 0; 9238c2ecf20Sopenharmony_ci} 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci/* 9268c2ecf20Sopenharmony_ci * User bit sync mode: 9278c2ecf20Sopenharmony_ci * 1 CD User channel subcode 9288c2ecf20Sopenharmony_ci * 0 Non-CD data 9298c2ecf20Sopenharmony_ci */ 9308c2ecf20Sopenharmony_cistatic int fsl_spdif_usync_put(struct snd_kcontrol *kcontrol, 9318c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 9348c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = snd_soc_dai_get_drvdata(cpu_dai); 9358c2ecf20Sopenharmony_ci struct regmap *regmap = spdif_priv->regmap; 9368c2ecf20Sopenharmony_ci u32 val = ucontrol->value.integer.value[0] << SRCD_CD_USER_OFFSET; 9378c2ecf20Sopenharmony_ci 9388c2ecf20Sopenharmony_ci regmap_update_bits(regmap, REG_SPDIF_SRCD, SRCD_CD_USER, val); 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci return 0; 9418c2ecf20Sopenharmony_ci} 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci/* FSL SPDIF IEC958 controller defines */ 9448c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new fsl_spdif_ctrls[] = { 9458c2ecf20Sopenharmony_ci /* Status cchanel controller */ 9468c2ecf20Sopenharmony_ci { 9478c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 9488c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), 9498c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 9508c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_WRITE | 9518c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 9528c2ecf20Sopenharmony_ci .info = fsl_spdif_info, 9538c2ecf20Sopenharmony_ci .get = fsl_spdif_pb_get, 9548c2ecf20Sopenharmony_ci .put = fsl_spdif_pb_put, 9558c2ecf20Sopenharmony_ci }, 9568c2ecf20Sopenharmony_ci { 9578c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9588c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 9598c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 9608c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 9618c2ecf20Sopenharmony_ci .info = fsl_spdif_info, 9628c2ecf20Sopenharmony_ci .get = fsl_spdif_capture_get, 9638c2ecf20Sopenharmony_ci }, 9648c2ecf20Sopenharmony_ci /* User bits controller */ 9658c2ecf20Sopenharmony_ci { 9668c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9678c2ecf20Sopenharmony_ci .name = "IEC958 Subcode Capture Default", 9688c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 9698c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 9708c2ecf20Sopenharmony_ci .info = fsl_spdif_info, 9718c2ecf20Sopenharmony_ci .get = fsl_spdif_subcode_get, 9728c2ecf20Sopenharmony_ci }, 9738c2ecf20Sopenharmony_ci { 9748c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9758c2ecf20Sopenharmony_ci .name = "IEC958 Q-subcode Capture Default", 9768c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 9778c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 9788c2ecf20Sopenharmony_ci .info = fsl_spdif_qinfo, 9798c2ecf20Sopenharmony_ci .get = fsl_spdif_qget, 9808c2ecf20Sopenharmony_ci }, 9818c2ecf20Sopenharmony_ci /* Valid bit error controller */ 9828c2ecf20Sopenharmony_ci { 9838c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9848c2ecf20Sopenharmony_ci .name = "IEC958 RX V-Bit Errors", 9858c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 9868c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 9878c2ecf20Sopenharmony_ci .info = fsl_spdif_vbit_info, 9888c2ecf20Sopenharmony_ci .get = fsl_spdif_rx_vbit_get, 9898c2ecf20Sopenharmony_ci }, 9908c2ecf20Sopenharmony_ci { 9918c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 9928c2ecf20Sopenharmony_ci .name = "IEC958 TX V-Bit", 9938c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 9948c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_WRITE | 9958c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 9968c2ecf20Sopenharmony_ci .info = fsl_spdif_vbit_info, 9978c2ecf20Sopenharmony_ci .get = fsl_spdif_tx_vbit_get, 9988c2ecf20Sopenharmony_ci .put = fsl_spdif_tx_vbit_put, 9998c2ecf20Sopenharmony_ci }, 10008c2ecf20Sopenharmony_ci /* DPLL lock info get controller */ 10018c2ecf20Sopenharmony_ci { 10028c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10038c2ecf20Sopenharmony_ci .name = "RX Sample Rate", 10048c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 10058c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 10068c2ecf20Sopenharmony_ci .info = fsl_spdif_rxrate_info, 10078c2ecf20Sopenharmony_ci .get = fsl_spdif_rxrate_get, 10088c2ecf20Sopenharmony_ci }, 10098c2ecf20Sopenharmony_ci /* User bit sync mode set/get controller */ 10108c2ecf20Sopenharmony_ci { 10118c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 10128c2ecf20Sopenharmony_ci .name = "IEC958 USyncMode CDText", 10138c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 10148c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_WRITE | 10158c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 10168c2ecf20Sopenharmony_ci .info = fsl_spdif_usync_info, 10178c2ecf20Sopenharmony_ci .get = fsl_spdif_usync_get, 10188c2ecf20Sopenharmony_ci .put = fsl_spdif_usync_put, 10198c2ecf20Sopenharmony_ci }, 10208c2ecf20Sopenharmony_ci}; 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic int fsl_spdif_dai_probe(struct snd_soc_dai *dai) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_private = snd_soc_dai_get_drvdata(dai); 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, &spdif_private->dma_params_tx, 10278c2ecf20Sopenharmony_ci &spdif_private->dma_params_rx); 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci snd_soc_add_dai_controls(dai, fsl_spdif_ctrls, ARRAY_SIZE(fsl_spdif_ctrls)); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /*Clear the val bit for Tx*/ 10328c2ecf20Sopenharmony_ci regmap_update_bits(spdif_private->regmap, REG_SPDIF_SCR, 10338c2ecf20Sopenharmony_ci SCR_VAL_MASK, SCR_VAL_CLEAR); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci return 0; 10368c2ecf20Sopenharmony_ci} 10378c2ecf20Sopenharmony_ci 10388c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver fsl_spdif_dai = { 10398c2ecf20Sopenharmony_ci .probe = &fsl_spdif_dai_probe, 10408c2ecf20Sopenharmony_ci .playback = { 10418c2ecf20Sopenharmony_ci .stream_name = "CPU-Playback", 10428c2ecf20Sopenharmony_ci .channels_min = 2, 10438c2ecf20Sopenharmony_ci .channels_max = 2, 10448c2ecf20Sopenharmony_ci .rates = FSL_SPDIF_RATES_PLAYBACK, 10458c2ecf20Sopenharmony_ci .formats = FSL_SPDIF_FORMATS_PLAYBACK, 10468c2ecf20Sopenharmony_ci }, 10478c2ecf20Sopenharmony_ci .capture = { 10488c2ecf20Sopenharmony_ci .stream_name = "CPU-Capture", 10498c2ecf20Sopenharmony_ci .channels_min = 2, 10508c2ecf20Sopenharmony_ci .channels_max = 2, 10518c2ecf20Sopenharmony_ci .rates = FSL_SPDIF_RATES_CAPTURE, 10528c2ecf20Sopenharmony_ci .formats = FSL_SPDIF_FORMATS_CAPTURE, 10538c2ecf20Sopenharmony_ci }, 10548c2ecf20Sopenharmony_ci .ops = &fsl_spdif_dai_ops, 10558c2ecf20Sopenharmony_ci}; 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver fsl_spdif_component = { 10588c2ecf20Sopenharmony_ci .name = "fsl-spdif", 10598c2ecf20Sopenharmony_ci}; 10608c2ecf20Sopenharmony_ci 10618c2ecf20Sopenharmony_ci/* FSL SPDIF REGMAP */ 10628c2ecf20Sopenharmony_cistatic const struct reg_default fsl_spdif_reg_defaults[] = { 10638c2ecf20Sopenharmony_ci {REG_SPDIF_SCR, 0x00000400}, 10648c2ecf20Sopenharmony_ci {REG_SPDIF_SRCD, 0x00000000}, 10658c2ecf20Sopenharmony_ci {REG_SPDIF_SIE, 0x00000000}, 10668c2ecf20Sopenharmony_ci {REG_SPDIF_STL, 0x00000000}, 10678c2ecf20Sopenharmony_ci {REG_SPDIF_STR, 0x00000000}, 10688c2ecf20Sopenharmony_ci {REG_SPDIF_STCSCH, 0x00000000}, 10698c2ecf20Sopenharmony_ci {REG_SPDIF_STCSCL, 0x00000000}, 10708c2ecf20Sopenharmony_ci {REG_SPDIF_STC, 0x00020f00}, 10718c2ecf20Sopenharmony_ci}; 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_cistatic bool fsl_spdif_readable_reg(struct device *dev, unsigned int reg) 10748c2ecf20Sopenharmony_ci{ 10758c2ecf20Sopenharmony_ci switch (reg) { 10768c2ecf20Sopenharmony_ci case REG_SPDIF_SCR: 10778c2ecf20Sopenharmony_ci case REG_SPDIF_SRCD: 10788c2ecf20Sopenharmony_ci case REG_SPDIF_SRPC: 10798c2ecf20Sopenharmony_ci case REG_SPDIF_SIE: 10808c2ecf20Sopenharmony_ci case REG_SPDIF_SIS: 10818c2ecf20Sopenharmony_ci case REG_SPDIF_SRL: 10828c2ecf20Sopenharmony_ci case REG_SPDIF_SRR: 10838c2ecf20Sopenharmony_ci case REG_SPDIF_SRCSH: 10848c2ecf20Sopenharmony_ci case REG_SPDIF_SRCSL: 10858c2ecf20Sopenharmony_ci case REG_SPDIF_SRU: 10868c2ecf20Sopenharmony_ci case REG_SPDIF_SRQ: 10878c2ecf20Sopenharmony_ci case REG_SPDIF_STCSCH: 10888c2ecf20Sopenharmony_ci case REG_SPDIF_STCSCL: 10898c2ecf20Sopenharmony_ci case REG_SPDIF_SRFM: 10908c2ecf20Sopenharmony_ci case REG_SPDIF_STC: 10918c2ecf20Sopenharmony_ci return true; 10928c2ecf20Sopenharmony_ci default: 10938c2ecf20Sopenharmony_ci return false; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci} 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_cistatic bool fsl_spdif_volatile_reg(struct device *dev, unsigned int reg) 10988c2ecf20Sopenharmony_ci{ 10998c2ecf20Sopenharmony_ci switch (reg) { 11008c2ecf20Sopenharmony_ci case REG_SPDIF_SRPC: 11018c2ecf20Sopenharmony_ci case REG_SPDIF_SIS: 11028c2ecf20Sopenharmony_ci case REG_SPDIF_SRL: 11038c2ecf20Sopenharmony_ci case REG_SPDIF_SRR: 11048c2ecf20Sopenharmony_ci case REG_SPDIF_SRCSH: 11058c2ecf20Sopenharmony_ci case REG_SPDIF_SRCSL: 11068c2ecf20Sopenharmony_ci case REG_SPDIF_SRU: 11078c2ecf20Sopenharmony_ci case REG_SPDIF_SRQ: 11088c2ecf20Sopenharmony_ci case REG_SPDIF_SRFM: 11098c2ecf20Sopenharmony_ci return true; 11108c2ecf20Sopenharmony_ci default: 11118c2ecf20Sopenharmony_ci return false; 11128c2ecf20Sopenharmony_ci } 11138c2ecf20Sopenharmony_ci} 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_cistatic bool fsl_spdif_writeable_reg(struct device *dev, unsigned int reg) 11168c2ecf20Sopenharmony_ci{ 11178c2ecf20Sopenharmony_ci switch (reg) { 11188c2ecf20Sopenharmony_ci case REG_SPDIF_SCR: 11198c2ecf20Sopenharmony_ci case REG_SPDIF_SRCD: 11208c2ecf20Sopenharmony_ci case REG_SPDIF_SRPC: 11218c2ecf20Sopenharmony_ci case REG_SPDIF_SIE: 11228c2ecf20Sopenharmony_ci case REG_SPDIF_SIC: 11238c2ecf20Sopenharmony_ci case REG_SPDIF_STL: 11248c2ecf20Sopenharmony_ci case REG_SPDIF_STR: 11258c2ecf20Sopenharmony_ci case REG_SPDIF_STCSCH: 11268c2ecf20Sopenharmony_ci case REG_SPDIF_STCSCL: 11278c2ecf20Sopenharmony_ci case REG_SPDIF_STC: 11288c2ecf20Sopenharmony_ci return true; 11298c2ecf20Sopenharmony_ci default: 11308c2ecf20Sopenharmony_ci return false; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci} 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_cistatic const struct regmap_config fsl_spdif_regmap_config = { 11358c2ecf20Sopenharmony_ci .reg_bits = 32, 11368c2ecf20Sopenharmony_ci .reg_stride = 4, 11378c2ecf20Sopenharmony_ci .val_bits = 32, 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_ci .max_register = REG_SPDIF_STC, 11408c2ecf20Sopenharmony_ci .reg_defaults = fsl_spdif_reg_defaults, 11418c2ecf20Sopenharmony_ci .num_reg_defaults = ARRAY_SIZE(fsl_spdif_reg_defaults), 11428c2ecf20Sopenharmony_ci .readable_reg = fsl_spdif_readable_reg, 11438c2ecf20Sopenharmony_ci .volatile_reg = fsl_spdif_volatile_reg, 11448c2ecf20Sopenharmony_ci .writeable_reg = fsl_spdif_writeable_reg, 11458c2ecf20Sopenharmony_ci .cache_type = REGCACHE_FLAT, 11468c2ecf20Sopenharmony_ci}; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_cistatic u32 fsl_spdif_txclk_caldiv(struct fsl_spdif_priv *spdif_priv, 11498c2ecf20Sopenharmony_ci struct clk *clk, u64 savesub, 11508c2ecf20Sopenharmony_ci enum spdif_txrate index, bool round) 11518c2ecf20Sopenharmony_ci{ 11528c2ecf20Sopenharmony_ci static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; 11538c2ecf20Sopenharmony_ci bool is_sysclk = clk_is_match(clk, spdif_priv->sysclk); 11548c2ecf20Sopenharmony_ci u64 rate_ideal, rate_actual, sub; 11558c2ecf20Sopenharmony_ci u32 arate; 11568c2ecf20Sopenharmony_ci u16 sysclk_dfmin, sysclk_dfmax, sysclk_df; 11578c2ecf20Sopenharmony_ci u8 txclk_df; 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci /* The sysclk has an extra divisor [2, 512] */ 11608c2ecf20Sopenharmony_ci sysclk_dfmin = is_sysclk ? 2 : 1; 11618c2ecf20Sopenharmony_ci sysclk_dfmax = is_sysclk ? 512 : 1; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci for (sysclk_df = sysclk_dfmin; sysclk_df <= sysclk_dfmax; sysclk_df++) { 11648c2ecf20Sopenharmony_ci for (txclk_df = 1; txclk_df <= 128; txclk_df++) { 11658c2ecf20Sopenharmony_ci rate_ideal = rate[index] * txclk_df * 64ULL; 11668c2ecf20Sopenharmony_ci if (round) 11678c2ecf20Sopenharmony_ci rate_actual = clk_round_rate(clk, rate_ideal); 11688c2ecf20Sopenharmony_ci else 11698c2ecf20Sopenharmony_ci rate_actual = clk_get_rate(clk); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci arate = rate_actual / 64; 11728c2ecf20Sopenharmony_ci arate /= txclk_df * sysclk_df; 11738c2ecf20Sopenharmony_ci 11748c2ecf20Sopenharmony_ci if (arate == rate[index]) { 11758c2ecf20Sopenharmony_ci /* We are lucky */ 11768c2ecf20Sopenharmony_ci savesub = 0; 11778c2ecf20Sopenharmony_ci spdif_priv->txclk_df[index] = txclk_df; 11788c2ecf20Sopenharmony_ci spdif_priv->sysclk_df[index] = sysclk_df; 11798c2ecf20Sopenharmony_ci spdif_priv->txrate[index] = arate; 11808c2ecf20Sopenharmony_ci goto out; 11818c2ecf20Sopenharmony_ci } else if (arate / rate[index] == 1) { 11828c2ecf20Sopenharmony_ci /* A little bigger than expect */ 11838c2ecf20Sopenharmony_ci sub = (u64)(arate - rate[index]) * 100000; 11848c2ecf20Sopenharmony_ci do_div(sub, rate[index]); 11858c2ecf20Sopenharmony_ci if (sub >= savesub) 11868c2ecf20Sopenharmony_ci continue; 11878c2ecf20Sopenharmony_ci savesub = sub; 11888c2ecf20Sopenharmony_ci spdif_priv->txclk_df[index] = txclk_df; 11898c2ecf20Sopenharmony_ci spdif_priv->sysclk_df[index] = sysclk_df; 11908c2ecf20Sopenharmony_ci spdif_priv->txrate[index] = arate; 11918c2ecf20Sopenharmony_ci } else if (rate[index] / arate == 1) { 11928c2ecf20Sopenharmony_ci /* A little smaller than expect */ 11938c2ecf20Sopenharmony_ci sub = (u64)(rate[index] - arate) * 100000; 11948c2ecf20Sopenharmony_ci do_div(sub, rate[index]); 11958c2ecf20Sopenharmony_ci if (sub >= savesub) 11968c2ecf20Sopenharmony_ci continue; 11978c2ecf20Sopenharmony_ci savesub = sub; 11988c2ecf20Sopenharmony_ci spdif_priv->txclk_df[index] = txclk_df; 11998c2ecf20Sopenharmony_ci spdif_priv->sysclk_df[index] = sysclk_df; 12008c2ecf20Sopenharmony_ci spdif_priv->txrate[index] = arate; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci } 12038c2ecf20Sopenharmony_ci } 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ciout: 12068c2ecf20Sopenharmony_ci return savesub; 12078c2ecf20Sopenharmony_ci} 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_cistatic int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, 12108c2ecf20Sopenharmony_ci enum spdif_txrate index) 12118c2ecf20Sopenharmony_ci{ 12128c2ecf20Sopenharmony_ci static const u32 rate[] = { 32000, 44100, 48000, 96000, 192000 }; 12138c2ecf20Sopenharmony_ci struct platform_device *pdev = spdif_priv->pdev; 12148c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 12158c2ecf20Sopenharmony_ci u64 savesub = 100000, ret; 12168c2ecf20Sopenharmony_ci struct clk *clk; 12178c2ecf20Sopenharmony_ci char tmp[16]; 12188c2ecf20Sopenharmony_ci int i; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci for (i = 0; i < STC_TXCLK_SRC_MAX; i++) { 12218c2ecf20Sopenharmony_ci sprintf(tmp, "rxtx%d", i); 12228c2ecf20Sopenharmony_ci clk = devm_clk_get(&pdev->dev, tmp); 12238c2ecf20Sopenharmony_ci if (IS_ERR(clk)) { 12248c2ecf20Sopenharmony_ci dev_err(dev, "no rxtx%d clock in devicetree\n", i); 12258c2ecf20Sopenharmony_ci return PTR_ERR(clk); 12268c2ecf20Sopenharmony_ci } 12278c2ecf20Sopenharmony_ci if (!clk_get_rate(clk)) 12288c2ecf20Sopenharmony_ci continue; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci ret = fsl_spdif_txclk_caldiv(spdif_priv, clk, savesub, index, 12318c2ecf20Sopenharmony_ci fsl_spdif_can_set_clk_rate(spdif_priv, i)); 12328c2ecf20Sopenharmony_ci if (savesub == ret) 12338c2ecf20Sopenharmony_ci continue; 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci savesub = ret; 12368c2ecf20Sopenharmony_ci spdif_priv->txclk[index] = clk; 12378c2ecf20Sopenharmony_ci spdif_priv->txclk_src[index] = i; 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci /* To quick catch a divisor, we allow a 0.1% deviation */ 12408c2ecf20Sopenharmony_ci if (savesub < 100) 12418c2ecf20Sopenharmony_ci break; 12428c2ecf20Sopenharmony_ci } 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "use rxtx%d as tx clock source for %dHz sample rate\n", 12458c2ecf20Sopenharmony_ci spdif_priv->txclk_src[index], rate[index]); 12468c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "use txclk df %d for %dHz sample rate\n", 12478c2ecf20Sopenharmony_ci spdif_priv->txclk_df[index], rate[index]); 12488c2ecf20Sopenharmony_ci if (clk_is_match(spdif_priv->txclk[index], spdif_priv->sysclk)) 12498c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "use sysclk df %d for %dHz sample rate\n", 12508c2ecf20Sopenharmony_ci spdif_priv->sysclk_df[index], rate[index]); 12518c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "the best rate for %dHz sample rate is %dHz\n", 12528c2ecf20Sopenharmony_ci rate[index], spdif_priv->txrate[index]); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci return 0; 12558c2ecf20Sopenharmony_ci} 12568c2ecf20Sopenharmony_ci 12578c2ecf20Sopenharmony_cistatic int fsl_spdif_probe(struct platform_device *pdev) 12588c2ecf20Sopenharmony_ci{ 12598c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv; 12608c2ecf20Sopenharmony_ci struct spdif_mixer_control *ctrl; 12618c2ecf20Sopenharmony_ci struct resource *res; 12628c2ecf20Sopenharmony_ci void __iomem *regs; 12638c2ecf20Sopenharmony_ci int irq, ret, i; 12648c2ecf20Sopenharmony_ci 12658c2ecf20Sopenharmony_ci spdif_priv = devm_kzalloc(&pdev->dev, sizeof(*spdif_priv), GFP_KERNEL); 12668c2ecf20Sopenharmony_ci if (!spdif_priv) 12678c2ecf20Sopenharmony_ci return -ENOMEM; 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_ci spdif_priv->pdev = pdev; 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci spdif_priv->soc = of_device_get_match_data(&pdev->dev); 12728c2ecf20Sopenharmony_ci if (!spdif_priv->soc) { 12738c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get soc data\n"); 12748c2ecf20Sopenharmony_ci return -ENODEV; 12758c2ecf20Sopenharmony_ci } 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci /* Initialize this copy of the CPU DAI driver structure */ 12788c2ecf20Sopenharmony_ci memcpy(&spdif_priv->cpu_dai_drv, &fsl_spdif_dai, sizeof(fsl_spdif_dai)); 12798c2ecf20Sopenharmony_ci spdif_priv->cpu_dai_drv.name = dev_name(&pdev->dev); 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci /* Get the addresses and IRQ */ 12828c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 12838c2ecf20Sopenharmony_ci regs = devm_ioremap_resource(&pdev->dev, res); 12848c2ecf20Sopenharmony_ci if (IS_ERR(regs)) 12858c2ecf20Sopenharmony_ci return PTR_ERR(regs); 12868c2ecf20Sopenharmony_ci 12878c2ecf20Sopenharmony_ci spdif_priv->regmap = devm_regmap_init_mmio_clk(&pdev->dev, 12888c2ecf20Sopenharmony_ci "core", regs, &fsl_spdif_regmap_config); 12898c2ecf20Sopenharmony_ci if (IS_ERR(spdif_priv->regmap)) { 12908c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "regmap init failed\n"); 12918c2ecf20Sopenharmony_ci return PTR_ERR(spdif_priv->regmap); 12928c2ecf20Sopenharmony_ci } 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 12958c2ecf20Sopenharmony_ci if (irq < 0) 12968c2ecf20Sopenharmony_ci return irq; 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, spdif_isr, 0, 12998c2ecf20Sopenharmony_ci dev_name(&pdev->dev), spdif_priv); 13008c2ecf20Sopenharmony_ci if (ret) { 13018c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "could not claim irq %u\n", irq); 13028c2ecf20Sopenharmony_ci return ret; 13038c2ecf20Sopenharmony_ci } 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci /* Get system clock for rx clock rate calculation */ 13068c2ecf20Sopenharmony_ci spdif_priv->sysclk = devm_clk_get(&pdev->dev, "rxtx5"); 13078c2ecf20Sopenharmony_ci if (IS_ERR(spdif_priv->sysclk)) { 13088c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no sys clock (rxtx5) in devicetree\n"); 13098c2ecf20Sopenharmony_ci return PTR_ERR(spdif_priv->sysclk); 13108c2ecf20Sopenharmony_ci } 13118c2ecf20Sopenharmony_ci 13128c2ecf20Sopenharmony_ci /* Get core clock for data register access via DMA */ 13138c2ecf20Sopenharmony_ci spdif_priv->coreclk = devm_clk_get(&pdev->dev, "core"); 13148c2ecf20Sopenharmony_ci if (IS_ERR(spdif_priv->coreclk)) { 13158c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no core clock in devicetree\n"); 13168c2ecf20Sopenharmony_ci return PTR_ERR(spdif_priv->coreclk); 13178c2ecf20Sopenharmony_ci } 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci spdif_priv->spbaclk = devm_clk_get(&pdev->dev, "spba"); 13208c2ecf20Sopenharmony_ci if (IS_ERR(spdif_priv->spbaclk)) 13218c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "no spba clock in devicetree\n"); 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci /* Select clock source for rx/tx clock */ 13248c2ecf20Sopenharmony_ci spdif_priv->rxclk = devm_clk_get(&pdev->dev, "rxtx1"); 13258c2ecf20Sopenharmony_ci if (IS_ERR(spdif_priv->rxclk)) { 13268c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "no rxtx1 clock in devicetree\n"); 13278c2ecf20Sopenharmony_ci return PTR_ERR(spdif_priv->rxclk); 13288c2ecf20Sopenharmony_ci } 13298c2ecf20Sopenharmony_ci spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; 13308c2ecf20Sopenharmony_ci 13318c2ecf20Sopenharmony_ci for (i = 0; i < SPDIF_TXRATE_MAX; i++) { 13328c2ecf20Sopenharmony_ci ret = fsl_spdif_probe_txclk(spdif_priv, i); 13338c2ecf20Sopenharmony_ci if (ret) 13348c2ecf20Sopenharmony_ci return ret; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci 13378c2ecf20Sopenharmony_ci /* Initial spinlock for control data */ 13388c2ecf20Sopenharmony_ci ctrl = &spdif_priv->fsl_spdif_control; 13398c2ecf20Sopenharmony_ci spin_lock_init(&ctrl->ctl_lock); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* Init tx channel status default value */ 13428c2ecf20Sopenharmony_ci ctrl->ch_status[0] = IEC958_AES0_CON_NOT_COPYRIGHT | 13438c2ecf20Sopenharmony_ci IEC958_AES0_CON_EMPHASIS_5015; 13448c2ecf20Sopenharmony_ci ctrl->ch_status[1] = IEC958_AES1_CON_DIGDIGCONV_ID; 13458c2ecf20Sopenharmony_ci ctrl->ch_status[2] = 0x00; 13468c2ecf20Sopenharmony_ci ctrl->ch_status[3] = IEC958_AES3_CON_FS_44100 | 13478c2ecf20Sopenharmony_ci IEC958_AES3_CON_CLOCK_1000PPM; 13488c2ecf20Sopenharmony_ci 13498c2ecf20Sopenharmony_ci spdif_priv->dpll_locked = false; 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci spdif_priv->dma_params_tx.maxburst = FSL_SPDIF_TXFIFO_WML; 13528c2ecf20Sopenharmony_ci spdif_priv->dma_params_rx.maxburst = FSL_SPDIF_RXFIFO_WML; 13538c2ecf20Sopenharmony_ci spdif_priv->dma_params_tx.addr = res->start + REG_SPDIF_STL; 13548c2ecf20Sopenharmony_ci spdif_priv->dma_params_rx.addr = res->start + REG_SPDIF_SRL; 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci /* Register with ASoC */ 13578c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->dev, spdif_priv); 13588c2ecf20Sopenharmony_ci pm_runtime_enable(&pdev->dev); 13598c2ecf20Sopenharmony_ci regcache_cache_only(spdif_priv->regmap, true); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci ret = devm_snd_soc_register_component(&pdev->dev, &fsl_spdif_component, 13628c2ecf20Sopenharmony_ci &spdif_priv->cpu_dai_drv, 1); 13638c2ecf20Sopenharmony_ci if (ret) { 13648c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register DAI: %d\n", ret); 13658c2ecf20Sopenharmony_ci goto err_pm_disable; 13668c2ecf20Sopenharmony_ci } 13678c2ecf20Sopenharmony_ci 13688c2ecf20Sopenharmony_ci ret = imx_pcm_dma_init(pdev, IMX_SPDIF_DMABUF_SIZE); 13698c2ecf20Sopenharmony_ci if (ret) { 13708c2ecf20Sopenharmony_ci dev_err_probe(&pdev->dev, ret, "imx_pcm_dma_init failed\n"); 13718c2ecf20Sopenharmony_ci goto err_pm_disable; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return ret; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_cierr_pm_disable: 13778c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 13788c2ecf20Sopenharmony_ci return ret; 13798c2ecf20Sopenharmony_ci} 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_cistatic int fsl_spdif_remove(struct platform_device *pdev) 13828c2ecf20Sopenharmony_ci{ 13838c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci return 0; 13868c2ecf20Sopenharmony_ci} 13878c2ecf20Sopenharmony_ci 13888c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 13898c2ecf20Sopenharmony_cistatic int fsl_spdif_runtime_suspend(struct device *dev) 13908c2ecf20Sopenharmony_ci{ 13918c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); 13928c2ecf20Sopenharmony_ci int i; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci /* Disable all the interrupts */ 13958c2ecf20Sopenharmony_ci regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SIE, 0xffffff, 0); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci regmap_read(spdif_priv->regmap, REG_SPDIF_SRPC, 13988c2ecf20Sopenharmony_ci &spdif_priv->regcache_srpc); 13998c2ecf20Sopenharmony_ci regcache_cache_only(spdif_priv->regmap, true); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->rxclk); 14028c2ecf20Sopenharmony_ci 14038c2ecf20Sopenharmony_ci for (i = 0; i < SPDIF_TXRATE_MAX; i++) 14048c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->txclk[i]); 14058c2ecf20Sopenharmony_ci 14068c2ecf20Sopenharmony_ci if (!IS_ERR(spdif_priv->spbaclk)) 14078c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->spbaclk); 14088c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->coreclk); 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_ci return 0; 14118c2ecf20Sopenharmony_ci} 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_cistatic int fsl_spdif_runtime_resume(struct device *dev) 14148c2ecf20Sopenharmony_ci{ 14158c2ecf20Sopenharmony_ci struct fsl_spdif_priv *spdif_priv = dev_get_drvdata(dev); 14168c2ecf20Sopenharmony_ci int ret; 14178c2ecf20Sopenharmony_ci int i; 14188c2ecf20Sopenharmony_ci 14198c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdif_priv->coreclk); 14208c2ecf20Sopenharmony_ci if (ret) { 14218c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable core clock\n"); 14228c2ecf20Sopenharmony_ci return ret; 14238c2ecf20Sopenharmony_ci } 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci if (!IS_ERR(spdif_priv->spbaclk)) { 14268c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdif_priv->spbaclk); 14278c2ecf20Sopenharmony_ci if (ret) { 14288c2ecf20Sopenharmony_ci dev_err(dev, "failed to enable spba clock\n"); 14298c2ecf20Sopenharmony_ci goto disable_core_clk; 14308c2ecf20Sopenharmony_ci } 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci for (i = 0; i < SPDIF_TXRATE_MAX; i++) { 14348c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdif_priv->txclk[i]); 14358c2ecf20Sopenharmony_ci if (ret) 14368c2ecf20Sopenharmony_ci goto disable_tx_clk; 14378c2ecf20Sopenharmony_ci } 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdif_priv->rxclk); 14408c2ecf20Sopenharmony_ci if (ret) 14418c2ecf20Sopenharmony_ci goto disable_tx_clk; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci regcache_cache_only(spdif_priv->regmap, false); 14448c2ecf20Sopenharmony_ci regcache_mark_dirty(spdif_priv->regmap); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci regmap_update_bits(spdif_priv->regmap, REG_SPDIF_SRPC, 14478c2ecf20Sopenharmony_ci SRPC_CLKSRC_SEL_MASK | SRPC_GAINSEL_MASK, 14488c2ecf20Sopenharmony_ci spdif_priv->regcache_srpc); 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci ret = regcache_sync(spdif_priv->regmap); 14518c2ecf20Sopenharmony_ci if (ret) 14528c2ecf20Sopenharmony_ci goto disable_rx_clk; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci return 0; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_cidisable_rx_clk: 14578c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->rxclk); 14588c2ecf20Sopenharmony_cidisable_tx_clk: 14598c2ecf20Sopenharmony_ci for (i--; i >= 0; i--) 14608c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->txclk[i]); 14618c2ecf20Sopenharmony_ci if (!IS_ERR(spdif_priv->spbaclk)) 14628c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->spbaclk); 14638c2ecf20Sopenharmony_cidisable_core_clk: 14648c2ecf20Sopenharmony_ci clk_disable_unprepare(spdif_priv->coreclk); 14658c2ecf20Sopenharmony_ci 14668c2ecf20Sopenharmony_ci return ret; 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_cistatic const struct dev_pm_ops fsl_spdif_pm = { 14718c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, 14728c2ecf20Sopenharmony_ci pm_runtime_force_resume) 14738c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(fsl_spdif_runtime_suspend, fsl_spdif_runtime_resume, 14748c2ecf20Sopenharmony_ci NULL) 14758c2ecf20Sopenharmony_ci}; 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_cistatic const struct of_device_id fsl_spdif_dt_ids[] = { 14788c2ecf20Sopenharmony_ci { .compatible = "fsl,imx35-spdif", .data = &fsl_spdif_imx35, }, 14798c2ecf20Sopenharmony_ci { .compatible = "fsl,vf610-spdif", .data = &fsl_spdif_vf610, }, 14808c2ecf20Sopenharmony_ci { .compatible = "fsl,imx6sx-spdif", .data = &fsl_spdif_imx6sx, }, 14818c2ecf20Sopenharmony_ci {} 14828c2ecf20Sopenharmony_ci}; 14838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, fsl_spdif_dt_ids); 14848c2ecf20Sopenharmony_ci 14858c2ecf20Sopenharmony_cistatic struct platform_driver fsl_spdif_driver = { 14868c2ecf20Sopenharmony_ci .driver = { 14878c2ecf20Sopenharmony_ci .name = "fsl-spdif-dai", 14888c2ecf20Sopenharmony_ci .of_match_table = fsl_spdif_dt_ids, 14898c2ecf20Sopenharmony_ci .pm = &fsl_spdif_pm, 14908c2ecf20Sopenharmony_ci }, 14918c2ecf20Sopenharmony_ci .probe = fsl_spdif_probe, 14928c2ecf20Sopenharmony_ci .remove = fsl_spdif_remove, 14938c2ecf20Sopenharmony_ci}; 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cimodule_platform_driver(fsl_spdif_driver); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ciMODULE_AUTHOR("Freescale Semiconductor, Inc."); 14988c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Freescale S/PDIF CPU DAI Driver"); 14998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 15008c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:fsl-spdif-dai"); 1501