18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 68c2ecf20Sopenharmony_ci * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitfield.h> 108c2ecf20Sopenharmony_ci#include <linux/clk.h> 118c2ecf20Sopenharmony_ci#include <linux/completion.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 158c2ecf20Sopenharmony_ci#include <linux/regmap.h> 168c2ecf20Sopenharmony_ci#include <linux/reset.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 198c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci/* SPDIF-rx Register Map */ 228c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_CR 0x00 238c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_IMR 0x04 248c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_SR 0x08 258c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_IFCR 0x0C 268c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_DR 0x10 278c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_CSR 0x14 288c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_DIR 0x18 298c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_VERR 0x3F4 308c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_IDR 0x3F8 318c2ecf20Sopenharmony_ci#define STM32_SPDIFRX_SIDR 0x3FC 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/* Bit definition for SPDIF_CR register */ 348c2ecf20Sopenharmony_ci#define SPDIFRX_CR_SPDIFEN_SHIFT 0 358c2ecf20Sopenharmony_ci#define SPDIFRX_CR_SPDIFEN_MASK GENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) 368c2ecf20Sopenharmony_ci#define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SPDIFRX_CR_RXDMAEN BIT(2) 398c2ecf20Sopenharmony_ci#define SPDIFRX_CR_RXSTEO BIT(3) 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define SPDIFRX_CR_DRFMT_SHIFT 4 428c2ecf20Sopenharmony_ci#define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) 438c2ecf20Sopenharmony_ci#define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SPDIFRX_CR_PMSK BIT(6) 468c2ecf20Sopenharmony_ci#define SPDIFRX_CR_VMSK BIT(7) 478c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CUMSK BIT(8) 488c2ecf20Sopenharmony_ci#define SPDIFRX_CR_PTMSK BIT(9) 498c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CBDMAEN BIT(10) 508c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CHSEL_SHIFT 11 518c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci#define SPDIFRX_CR_NBTR_SHIFT 12 548c2ecf20Sopenharmony_ci#define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) 558c2ecf20Sopenharmony_ci#define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define SPDIFRX_CR_WFA BIT(14) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci#define SPDIFRX_CR_INSEL_SHIFT 16 608c2ecf20Sopenharmony_ci#define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) 618c2ecf20Sopenharmony_ci#define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CKSEN_SHIFT 20 648c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CKSEN BIT(20) 658c2ecf20Sopenharmony_ci#define SPDIFRX_CR_CKSBKPEN BIT(21) 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_IMR register */ 688c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_RXNEI BIT(0) 698c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_CSRNEIE BIT(1) 708c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_PERRIE BIT(2) 718c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_OVRIE BIT(3) 728c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_SBLKIE BIT(4) 738c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_SYNCDIE BIT(5) 748c2ecf20Sopenharmony_ci#define SPDIFRX_IMR_IFEIE BIT(6) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci#define SPDIFRX_XIMR_MASK GENMASK(6, 0) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_SR register */ 798c2ecf20Sopenharmony_ci#define SPDIFRX_SR_RXNE BIT(0) 808c2ecf20Sopenharmony_ci#define SPDIFRX_SR_CSRNE BIT(1) 818c2ecf20Sopenharmony_ci#define SPDIFRX_SR_PERR BIT(2) 828c2ecf20Sopenharmony_ci#define SPDIFRX_SR_OVR BIT(3) 838c2ecf20Sopenharmony_ci#define SPDIFRX_SR_SBD BIT(4) 848c2ecf20Sopenharmony_ci#define SPDIFRX_SR_SYNCD BIT(5) 858c2ecf20Sopenharmony_ci#define SPDIFRX_SR_FERR BIT(6) 868c2ecf20Sopenharmony_ci#define SPDIFRX_SR_SERR BIT(7) 878c2ecf20Sopenharmony_ci#define SPDIFRX_SR_TERR BIT(8) 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci#define SPDIFRX_SR_WIDTH5_SHIFT 16 908c2ecf20Sopenharmony_ci#define SPDIFRX_SR_WIDTH5_MASK GENMASK(30, PDIFRX_SR_WIDTH5_SHIFT) 918c2ecf20Sopenharmony_ci#define SPDIFRX_SR_WIDTH5SET(x) ((x) << SPDIFRX_SR_WIDTH5_SHIFT) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_IFCR register */ 948c2ecf20Sopenharmony_ci#define SPDIFRX_IFCR_PERRCF BIT(2) 958c2ecf20Sopenharmony_ci#define SPDIFRX_IFCR_OVRCF BIT(3) 968c2ecf20Sopenharmony_ci#define SPDIFRX_IFCR_SBDCF BIT(4) 978c2ecf20Sopenharmony_ci#define SPDIFRX_IFCR_SYNCDCF BIT(5) 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci#define SPDIFRX_XIFCR_MASK GENMASK(5, 2) 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_DR register (DRFMT = 0b00) */ 1028c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_DR_SHIFT 0 1038c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_DR_MASK GENMASK(23, SPDIFRX_DR0_DR_SHIFT) 1048c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_DRSET(x) ((x) << SPDIFRX_DR0_DR_SHIFT) 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_PE BIT(24) 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_V BIT(25) 1098c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_U BIT(26) 1108c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_C BIT(27) 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_PT_SHIFT 28 1138c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_PT_MASK GENMASK(29, SPDIFRX_DR0_PT_SHIFT) 1148c2ecf20Sopenharmony_ci#define SPDIFRX_DR0_PTSET(x) ((x) << SPDIFRX_DR0_PT_SHIFT) 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_DR register (DRFMT = 0b01) */ 1178c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_PE BIT(0) 1188c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_V BIT(1) 1198c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_U BIT(2) 1208c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_C BIT(3) 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_PT_SHIFT 4 1238c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_PT_MASK GENMASK(5, SPDIFRX_DR1_PT_SHIFT) 1248c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_PTSET(x) ((x) << SPDIFRX_DR1_PT_SHIFT) 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DR_SHIFT 8 1278c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DR_MASK GENMASK(31, SPDIFRX_DR1_DR_SHIFT) 1288c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRSET(x) ((x) << SPDIFRX_DR1_DR_SHIFT) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_DR register (DRFMT = 0b10) */ 1318c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRNL1_SHIFT 0 1328c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRNL1_MASK GENMASK(15, SPDIFRX_DR1_DRNL1_SHIFT) 1338c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRNL1SET(x) ((x) << SPDIFRX_DR1_DRNL1_SHIFT) 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRNL2_SHIFT 16 1368c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRNL2_MASK GENMASK(31, SPDIFRX_DR1_DRNL2_SHIFT) 1378c2ecf20Sopenharmony_ci#define SPDIFRX_DR1_DRNL2SET(x) ((x) << SPDIFRX_DR1_DRNL2_SHIFT) 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_CSR register */ 1408c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_USR_SHIFT 0 1418c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_USR_MASK GENMASK(15, SPDIFRX_CSR_USR_SHIFT) 1428c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_USRGET(x) (((x) & SPDIFRX_CSR_USR_MASK)\ 1438c2ecf20Sopenharmony_ci >> SPDIFRX_CSR_USR_SHIFT) 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_CS_SHIFT 16 1468c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_CS_MASK GENMASK(23, SPDIFRX_CSR_CS_SHIFT) 1478c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_CSGET(x) (((x) & SPDIFRX_CSR_CS_MASK)\ 1488c2ecf20Sopenharmony_ci >> SPDIFRX_CSR_CS_SHIFT) 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_SOB BIT(24) 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_DIR register */ 1538c2ecf20Sopenharmony_ci#define SPDIFRX_DIR_THI_SHIFT 0 1548c2ecf20Sopenharmony_ci#define SPDIFRX_DIR_THI_MASK GENMASK(12, SPDIFRX_DIR_THI_SHIFT) 1558c2ecf20Sopenharmony_ci#define SPDIFRX_DIR_THI_SET(x) ((x) << SPDIFRX_DIR_THI_SHIFT) 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci#define SPDIFRX_DIR_TLO_SHIFT 16 1588c2ecf20Sopenharmony_ci#define SPDIFRX_DIR_TLO_MASK GENMASK(28, SPDIFRX_DIR_TLO_SHIFT) 1598c2ecf20Sopenharmony_ci#define SPDIFRX_DIR_TLO_SET(x) ((x) << SPDIFRX_DIR_TLO_SHIFT) 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define SPDIFRX_SPDIFEN_DISABLE 0x0 1628c2ecf20Sopenharmony_ci#define SPDIFRX_SPDIFEN_SYNC 0x1 1638c2ecf20Sopenharmony_ci#define SPDIFRX_SPDIFEN_ENABLE 0x3 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_VERR register */ 1668c2ecf20Sopenharmony_ci#define SPDIFRX_VERR_MIN_MASK GENMASK(3, 0) 1678c2ecf20Sopenharmony_ci#define SPDIFRX_VERR_MAJ_MASK GENMASK(7, 4) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_IDR register */ 1708c2ecf20Sopenharmony_ci#define SPDIFRX_IDR_ID_MASK GENMASK(31, 0) 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* Bit definition for SPDIFRX_SIDR register */ 1738c2ecf20Sopenharmony_ci#define SPDIFRX_SIDR_SID_MASK GENMASK(31, 0) 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#define SPDIFRX_IPIDR_NUMBER 0x00130041 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci#define SPDIFRX_IN1 0x1 1788c2ecf20Sopenharmony_ci#define SPDIFRX_IN2 0x2 1798c2ecf20Sopenharmony_ci#define SPDIFRX_IN3 0x3 1808c2ecf20Sopenharmony_ci#define SPDIFRX_IN4 0x4 1818c2ecf20Sopenharmony_ci#define SPDIFRX_IN5 0x5 1828c2ecf20Sopenharmony_ci#define SPDIFRX_IN6 0x6 1838c2ecf20Sopenharmony_ci#define SPDIFRX_IN7 0x7 1848c2ecf20Sopenharmony_ci#define SPDIFRX_IN8 0x8 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci#define SPDIFRX_NBTR_NONE 0x0 1878c2ecf20Sopenharmony_ci#define SPDIFRX_NBTR_3 0x1 1888c2ecf20Sopenharmony_ci#define SPDIFRX_NBTR_15 0x2 1898c2ecf20Sopenharmony_ci#define SPDIFRX_NBTR_63 0x3 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci#define SPDIFRX_DRFMT_RIGHT 0x0 1928c2ecf20Sopenharmony_ci#define SPDIFRX_DRFMT_LEFT 0x1 1938c2ecf20Sopenharmony_ci#define SPDIFRX_DRFMT_PACKED 0x2 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci/* 192 CS bits in S/PDIF frame. i.e 24 CS bytes */ 1968c2ecf20Sopenharmony_ci#define SPDIFRX_CS_BYTES_NB 24 1978c2ecf20Sopenharmony_ci#define SPDIFRX_UB_BYTES_NB 48 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/* 2008c2ecf20Sopenharmony_ci * CSR register is retrieved as a 32 bits word 2018c2ecf20Sopenharmony_ci * It contains 1 channel status byte and 2 user data bytes 2028c2ecf20Sopenharmony_ci * 2 S/PDIF frames are acquired to get all CS/UB bits 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci#define SPDIFRX_CSR_BUF_LENGTH (SPDIFRX_CS_BYTES_NB * 4 * 2) 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci/** 2078c2ecf20Sopenharmony_ci * struct stm32_spdifrx_data - private data of SPDIFRX 2088c2ecf20Sopenharmony_ci * @pdev: device data pointer 2098c2ecf20Sopenharmony_ci * @base: mmio register base virtual address 2108c2ecf20Sopenharmony_ci * @regmap: SPDIFRX register map pointer 2118c2ecf20Sopenharmony_ci * @regmap_conf: SPDIFRX register map configuration pointer 2128c2ecf20Sopenharmony_ci * @cs_completion: channel status retrieving completion 2138c2ecf20Sopenharmony_ci * @kclk: kernel clock feeding the SPDIFRX clock generator 2148c2ecf20Sopenharmony_ci * @dma_params: dma configuration data for rx channel 2158c2ecf20Sopenharmony_ci * @substream: PCM substream data pointer 2168c2ecf20Sopenharmony_ci * @dmab: dma buffer info pointer 2178c2ecf20Sopenharmony_ci * @ctrl_chan: dma channel for S/PDIF control bits 2188c2ecf20Sopenharmony_ci * @desc:dma async transaction descriptor 2198c2ecf20Sopenharmony_ci * @slave_config: dma slave channel runtime config pointer 2208c2ecf20Sopenharmony_ci * @phys_addr: SPDIFRX registers physical base address 2218c2ecf20Sopenharmony_ci * @lock: synchronization enabling lock 2228c2ecf20Sopenharmony_ci * @irq_lock: prevent race condition with IRQ on stream state 2238c2ecf20Sopenharmony_ci * @cs: channel status buffer 2248c2ecf20Sopenharmony_ci * @ub: user data buffer 2258c2ecf20Sopenharmony_ci * @irq: SPDIFRX interrupt line 2268c2ecf20Sopenharmony_ci * @refcount: keep count of opened DMA channels 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_cistruct stm32_spdifrx_data { 2298c2ecf20Sopenharmony_ci struct platform_device *pdev; 2308c2ecf20Sopenharmony_ci void __iomem *base; 2318c2ecf20Sopenharmony_ci struct regmap *regmap; 2328c2ecf20Sopenharmony_ci const struct regmap_config *regmap_conf; 2338c2ecf20Sopenharmony_ci struct completion cs_completion; 2348c2ecf20Sopenharmony_ci struct clk *kclk; 2358c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data dma_params; 2368c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 2378c2ecf20Sopenharmony_ci struct snd_dma_buffer *dmab; 2388c2ecf20Sopenharmony_ci struct dma_chan *ctrl_chan; 2398c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *desc; 2408c2ecf20Sopenharmony_ci struct dma_slave_config slave_config; 2418c2ecf20Sopenharmony_ci dma_addr_t phys_addr; 2428c2ecf20Sopenharmony_ci spinlock_t lock; /* Sync enabling lock */ 2438c2ecf20Sopenharmony_ci spinlock_t irq_lock; /* Prevent race condition on stream state */ 2448c2ecf20Sopenharmony_ci unsigned char cs[SPDIFRX_CS_BYTES_NB]; 2458c2ecf20Sopenharmony_ci unsigned char ub[SPDIFRX_UB_BYTES_NB]; 2468c2ecf20Sopenharmony_ci int irq; 2478c2ecf20Sopenharmony_ci int refcount; 2488c2ecf20Sopenharmony_ci}; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic void stm32_spdifrx_dma_complete(void *data) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)data; 2538c2ecf20Sopenharmony_ci struct platform_device *pdev = spdifrx->pdev; 2548c2ecf20Sopenharmony_ci u32 *p_start = (u32 *)spdifrx->dmab->area; 2558c2ecf20Sopenharmony_ci u32 *p_end = p_start + (2 * SPDIFRX_CS_BYTES_NB) - 1; 2568c2ecf20Sopenharmony_ci u32 *ptr = p_start; 2578c2ecf20Sopenharmony_ci u16 *ub_ptr = (short *)spdifrx->ub; 2588c2ecf20Sopenharmony_ci int i = 0; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 2618c2ecf20Sopenharmony_ci SPDIFRX_CR_CBDMAEN, 2628c2ecf20Sopenharmony_ci (unsigned int)~SPDIFRX_CR_CBDMAEN); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci if (!spdifrx->dmab->area) 2658c2ecf20Sopenharmony_ci return; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci while (ptr <= p_end) { 2688c2ecf20Sopenharmony_ci if (*ptr & SPDIFRX_CSR_SOB) 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci ptr++; 2718c2ecf20Sopenharmony_ci } 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (ptr > p_end) { 2748c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Start of S/PDIF block not found\n"); 2758c2ecf20Sopenharmony_ci return; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci while (i < SPDIFRX_CS_BYTES_NB) { 2798c2ecf20Sopenharmony_ci spdifrx->cs[i] = (unsigned char)SPDIFRX_CSR_CSGET(*ptr); 2808c2ecf20Sopenharmony_ci *ub_ptr++ = SPDIFRX_CSR_USRGET(*ptr++); 2818c2ecf20Sopenharmony_ci if (ptr > p_end) { 2828c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Failed to get channel status\n"); 2838c2ecf20Sopenharmony_ci return; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci i++; 2868c2ecf20Sopenharmony_ci } 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci complete(&spdifrx->cs_completion); 2898c2ecf20Sopenharmony_ci} 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_cistatic int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx) 2928c2ecf20Sopenharmony_ci{ 2938c2ecf20Sopenharmony_ci dma_cookie_t cookie; 2948c2ecf20Sopenharmony_ci int err; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci spdifrx->desc = dmaengine_prep_slave_single(spdifrx->ctrl_chan, 2978c2ecf20Sopenharmony_ci spdifrx->dmab->addr, 2988c2ecf20Sopenharmony_ci SPDIFRX_CSR_BUF_LENGTH, 2998c2ecf20Sopenharmony_ci DMA_DEV_TO_MEM, 3008c2ecf20Sopenharmony_ci DMA_CTRL_ACK); 3018c2ecf20Sopenharmony_ci if (!spdifrx->desc) 3028c2ecf20Sopenharmony_ci return -EINVAL; 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci spdifrx->desc->callback = stm32_spdifrx_dma_complete; 3058c2ecf20Sopenharmony_ci spdifrx->desc->callback_param = spdifrx; 3068c2ecf20Sopenharmony_ci cookie = dmaengine_submit(spdifrx->desc); 3078c2ecf20Sopenharmony_ci err = dma_submit_error(cookie); 3088c2ecf20Sopenharmony_ci if (err) 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci dma_async_issue_pending(spdifrx->ctrl_chan); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_cistatic void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) 3178c2ecf20Sopenharmony_ci{ 3188c2ecf20Sopenharmony_ci dmaengine_terminate_async(spdifrx->ctrl_chan); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci int cr, cr_mask, imr, ret; 3248c2ecf20Sopenharmony_ci unsigned long flags; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Enable IRQs */ 3278c2ecf20Sopenharmony_ci imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; 3288c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, imr, imr); 3298c2ecf20Sopenharmony_ci if (ret) 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci spin_lock_irqsave(&spdifrx->lock, flags); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci spdifrx->refcount++; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci if (!(cr & SPDIFRX_CR_SPDIFEN_MASK)) { 3398c2ecf20Sopenharmony_ci /* 3408c2ecf20Sopenharmony_ci * Start sync if SPDIFRX is still in idle state. 3418c2ecf20Sopenharmony_ci * SPDIFRX reception enabled when sync done 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci dev_dbg(&spdifrx->pdev->dev, "start synchronization\n"); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci /* 3468c2ecf20Sopenharmony_ci * SPDIFRX configuration: 3478c2ecf20Sopenharmony_ci * Wait for activity before starting sync process. This avoid 3488c2ecf20Sopenharmony_ci * to issue sync errors when spdif signal is missing on input. 3498c2ecf20Sopenharmony_ci * Preamble, CS, user, validity and parity error bits not copied 3508c2ecf20Sopenharmony_ci * to DR register. 3518c2ecf20Sopenharmony_ci */ 3528c2ecf20Sopenharmony_ci cr = SPDIFRX_CR_WFA | SPDIFRX_CR_PMSK | SPDIFRX_CR_VMSK | 3538c2ecf20Sopenharmony_ci SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; 3548c2ecf20Sopenharmony_ci cr_mask = cr; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63); 3578c2ecf20Sopenharmony_ci cr_mask |= SPDIFRX_CR_NBTR_MASK; 3588c2ecf20Sopenharmony_ci cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); 3598c2ecf20Sopenharmony_ci cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; 3608c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 3618c2ecf20Sopenharmony_ci cr_mask, cr); 3628c2ecf20Sopenharmony_ci if (ret < 0) 3638c2ecf20Sopenharmony_ci dev_err(&spdifrx->pdev->dev, 3648c2ecf20Sopenharmony_ci "Failed to start synchronization\n"); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spdifrx->lock, flags); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci return ret; 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci int cr, cr_mask, reg; 3758c2ecf20Sopenharmony_ci unsigned long flags; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci spin_lock_irqsave(&spdifrx->lock, flags); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (--spdifrx->refcount) { 3808c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spdifrx->lock, flags); 3818c2ecf20Sopenharmony_ci return; 3828c2ecf20Sopenharmony_ci } 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); 3858c2ecf20Sopenharmony_ci cr_mask = SPDIFRX_CR_SPDIFEN_MASK | SPDIFRX_CR_RXDMAEN; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, cr_mask, cr); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, 3908c2ecf20Sopenharmony_ci SPDIFRX_XIMR_MASK, 0); 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, 3938c2ecf20Sopenharmony_ci SPDIFRX_XIFCR_MASK, SPDIFRX_XIFCR_MASK); 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci /* dummy read to clear CSRNE and RXNE in status register */ 3968c2ecf20Sopenharmony_ci regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); 3978c2ecf20Sopenharmony_ci regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spdifrx->lock, flags); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_cistatic int stm32_spdifrx_dma_ctrl_register(struct device *dev, 4038c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci int ret; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); 4088c2ecf20Sopenharmony_ci if (IS_ERR(spdifrx->ctrl_chan)) { 4098c2ecf20Sopenharmony_ci if (PTR_ERR(spdifrx->ctrl_chan) != -EPROBE_DEFER) 4108c2ecf20Sopenharmony_ci dev_err(dev, "dma_request_slave_channel error %ld\n", 4118c2ecf20Sopenharmony_ci PTR_ERR(spdifrx->ctrl_chan)); 4128c2ecf20Sopenharmony_ci return PTR_ERR(spdifrx->ctrl_chan); 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), 4168c2ecf20Sopenharmony_ci GFP_KERNEL); 4178c2ecf20Sopenharmony_ci if (!spdifrx->dmab) 4188c2ecf20Sopenharmony_ci return -ENOMEM; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM; 4218c2ecf20Sopenharmony_ci spdifrx->dmab->dev.dev = dev; 4228c2ecf20Sopenharmony_ci ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev, 4238c2ecf20Sopenharmony_ci SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab); 4248c2ecf20Sopenharmony_ci if (ret < 0) { 4258c2ecf20Sopenharmony_ci dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret); 4268c2ecf20Sopenharmony_ci return ret; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci spdifrx->slave_config.direction = DMA_DEV_TO_MEM; 4308c2ecf20Sopenharmony_ci spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + 4318c2ecf20Sopenharmony_ci STM32_SPDIFRX_CSR); 4328c2ecf20Sopenharmony_ci spdifrx->slave_config.dst_addr = spdifrx->dmab->addr; 4338c2ecf20Sopenharmony_ci spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 4348c2ecf20Sopenharmony_ci spdifrx->slave_config.src_maxburst = 1; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci ret = dmaengine_slave_config(spdifrx->ctrl_chan, 4378c2ecf20Sopenharmony_ci &spdifrx->slave_config); 4388c2ecf20Sopenharmony_ci if (ret < 0) { 4398c2ecf20Sopenharmony_ci dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); 4408c2ecf20Sopenharmony_ci spdifrx->ctrl_chan = NULL; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci return ret; 4448c2ecf20Sopenharmony_ci}; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_cistatic const char * const spdifrx_enum_input[] = { 4478c2ecf20Sopenharmony_ci "in0", "in1", "in2", "in3" 4488c2ecf20Sopenharmony_ci}; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci/* By default CS bits are retrieved from channel A */ 4518c2ecf20Sopenharmony_cistatic const char * const spdifrx_enum_cs_channel[] = { 4528c2ecf20Sopenharmony_ci "A", "B" 4538c2ecf20Sopenharmony_ci}; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(ctrl_enum_input, 4568c2ecf20Sopenharmony_ci STM32_SPDIFRX_CR, SPDIFRX_CR_INSEL_SHIFT, 4578c2ecf20Sopenharmony_ci spdifrx_enum_input); 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cistatic SOC_ENUM_SINGLE_DECL(ctrl_enum_cs_channel, 4608c2ecf20Sopenharmony_ci STM32_SPDIFRX_CR, SPDIFRX_CR_CHSEL_SHIFT, 4618c2ecf20Sopenharmony_ci spdifrx_enum_cs_channel); 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_cistatic int stm32_spdifrx_info(struct snd_kcontrol *kcontrol, 4648c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4658c2ecf20Sopenharmony_ci{ 4668c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 4678c2ecf20Sopenharmony_ci uinfo->count = 1; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci return 0; 4708c2ecf20Sopenharmony_ci} 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_cistatic int stm32_spdifrx_ub_info(struct snd_kcontrol *kcontrol, 4738c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4748c2ecf20Sopenharmony_ci{ 4758c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 4768c2ecf20Sopenharmony_ci uinfo->count = 1; 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) 4828c2ecf20Sopenharmony_ci{ 4838c2ecf20Sopenharmony_ci int ret = 0; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); 4868c2ecf20Sopenharmony_ci memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci ret = stm32_spdifrx_dma_ctrl_start(spdifrx); 4898c2ecf20Sopenharmony_ci if (ret < 0) 4908c2ecf20Sopenharmony_ci return ret; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdifrx->kclk); 4938c2ecf20Sopenharmony_ci if (ret) { 4948c2ecf20Sopenharmony_ci dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); 4958c2ecf20Sopenharmony_ci return ret; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 4998c2ecf20Sopenharmony_ci SPDIFRX_CR_CBDMAEN, SPDIFRX_CR_CBDMAEN); 5008c2ecf20Sopenharmony_ci if (ret < 0) 5018c2ecf20Sopenharmony_ci goto end; 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci ret = stm32_spdifrx_start_sync(spdifrx); 5048c2ecf20Sopenharmony_ci if (ret < 0) 5058c2ecf20Sopenharmony_ci goto end; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, 5088c2ecf20Sopenharmony_ci msecs_to_jiffies(100)) 5098c2ecf20Sopenharmony_ci <= 0) { 5108c2ecf20Sopenharmony_ci dev_dbg(&spdifrx->pdev->dev, "Failed to get control data\n"); 5118c2ecf20Sopenharmony_ci ret = -EAGAIN; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci stm32_spdifrx_stop(spdifrx); 5158c2ecf20Sopenharmony_ci stm32_spdifrx_dma_ctrl_stop(spdifrx); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ciend: 5188c2ecf20Sopenharmony_ci clk_disable_unprepare(spdifrx->kclk); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return ret; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int stm32_spdifrx_capture_get(struct snd_kcontrol *kcontrol, 5248c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 5278c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci stm32_spdifrx_get_ctrl_data(spdifrx); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = spdifrx->cs[0]; 5328c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = spdifrx->cs[1]; 5338c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = spdifrx->cs[2]; 5348c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = spdifrx->cs[3]; 5358c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[4] = spdifrx->cs[4]; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci return 0; 5388c2ecf20Sopenharmony_ci} 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_cistatic int stm32_spdif_user_bits_get(struct snd_kcontrol *kcontrol, 5418c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 5448c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci stm32_spdifrx_get_ctrl_data(spdifrx); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[0] = spdifrx->ub[0]; 5498c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[1] = spdifrx->ub[1]; 5508c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[2] = spdifrx->ub[2]; 5518c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[3] = spdifrx->ub[3]; 5528c2ecf20Sopenharmony_ci ucontrol->value.iec958.status[4] = spdifrx->ub[4]; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new stm32_spdifrx_iec_ctrls[] = { 5588c2ecf20Sopenharmony_ci /* Channel status control */ 5598c2ecf20Sopenharmony_ci { 5608c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 5618c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 5628c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 5638c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 5648c2ecf20Sopenharmony_ci .info = stm32_spdifrx_info, 5658c2ecf20Sopenharmony_ci .get = stm32_spdifrx_capture_get, 5668c2ecf20Sopenharmony_ci }, 5678c2ecf20Sopenharmony_ci /* User bits control */ 5688c2ecf20Sopenharmony_ci { 5698c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 5708c2ecf20Sopenharmony_ci .name = "IEC958 User Bit Capture Default", 5718c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 5728c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 5738c2ecf20Sopenharmony_ci .info = stm32_spdifrx_ub_info, 5748c2ecf20Sopenharmony_ci .get = stm32_spdif_user_bits_get, 5758c2ecf20Sopenharmony_ci }, 5768c2ecf20Sopenharmony_ci}; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new stm32_spdifrx_ctrls[] = { 5798c2ecf20Sopenharmony_ci SOC_ENUM("SPDIFRX input", ctrl_enum_input), 5808c2ecf20Sopenharmony_ci SOC_ENUM("SPDIFRX CS channel", ctrl_enum_cs_channel), 5818c2ecf20Sopenharmony_ci}; 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_cistatic int stm32_spdifrx_dai_register_ctrls(struct snd_soc_dai *cpu_dai) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci int ret; 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci ret = snd_soc_add_dai_controls(cpu_dai, stm32_spdifrx_iec_ctrls, 5888c2ecf20Sopenharmony_ci ARRAY_SIZE(stm32_spdifrx_iec_ctrls)); 5898c2ecf20Sopenharmony_ci if (ret < 0) 5908c2ecf20Sopenharmony_ci return ret; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return snd_soc_add_component_controls(cpu_dai->component, 5938c2ecf20Sopenharmony_ci stm32_spdifrx_ctrls, 5948c2ecf20Sopenharmony_ci ARRAY_SIZE(stm32_spdifrx_ctrls)); 5958c2ecf20Sopenharmony_ci} 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_cistatic int stm32_spdifrx_dai_probe(struct snd_soc_dai *cpu_dai) 5988c2ecf20Sopenharmony_ci{ 5998c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(cpu_dai->dev); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci spdifrx->dma_params.addr = (dma_addr_t)(spdifrx->phys_addr + 6028c2ecf20Sopenharmony_ci STM32_SPDIFRX_DR); 6038c2ecf20Sopenharmony_ci spdifrx->dma_params.maxburst = 1; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci return stm32_spdifrx_dai_register_ctrls(cpu_dai); 6088c2ecf20Sopenharmony_ci} 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_cistatic bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci switch (reg) { 6138c2ecf20Sopenharmony_ci case STM32_SPDIFRX_CR: 6148c2ecf20Sopenharmony_ci case STM32_SPDIFRX_IMR: 6158c2ecf20Sopenharmony_ci case STM32_SPDIFRX_SR: 6168c2ecf20Sopenharmony_ci case STM32_SPDIFRX_IFCR: 6178c2ecf20Sopenharmony_ci case STM32_SPDIFRX_DR: 6188c2ecf20Sopenharmony_ci case STM32_SPDIFRX_CSR: 6198c2ecf20Sopenharmony_ci case STM32_SPDIFRX_DIR: 6208c2ecf20Sopenharmony_ci case STM32_SPDIFRX_VERR: 6218c2ecf20Sopenharmony_ci case STM32_SPDIFRX_IDR: 6228c2ecf20Sopenharmony_ci case STM32_SPDIFRX_SIDR: 6238c2ecf20Sopenharmony_ci return true; 6248c2ecf20Sopenharmony_ci default: 6258c2ecf20Sopenharmony_ci return false; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cistatic bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) 6308c2ecf20Sopenharmony_ci{ 6318c2ecf20Sopenharmony_ci switch (reg) { 6328c2ecf20Sopenharmony_ci case STM32_SPDIFRX_DR: 6338c2ecf20Sopenharmony_ci case STM32_SPDIFRX_CSR: 6348c2ecf20Sopenharmony_ci case STM32_SPDIFRX_SR: 6358c2ecf20Sopenharmony_ci case STM32_SPDIFRX_DIR: 6368c2ecf20Sopenharmony_ci return true; 6378c2ecf20Sopenharmony_ci default: 6388c2ecf20Sopenharmony_ci return false; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci switch (reg) { 6458c2ecf20Sopenharmony_ci case STM32_SPDIFRX_CR: 6468c2ecf20Sopenharmony_ci case STM32_SPDIFRX_IMR: 6478c2ecf20Sopenharmony_ci case STM32_SPDIFRX_IFCR: 6488c2ecf20Sopenharmony_ci return true; 6498c2ecf20Sopenharmony_ci default: 6508c2ecf20Sopenharmony_ci return false; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci} 6538c2ecf20Sopenharmony_ci 6548c2ecf20Sopenharmony_cistatic const struct regmap_config stm32_h7_spdifrx_regmap_conf = { 6558c2ecf20Sopenharmony_ci .reg_bits = 32, 6568c2ecf20Sopenharmony_ci .reg_stride = 4, 6578c2ecf20Sopenharmony_ci .val_bits = 32, 6588c2ecf20Sopenharmony_ci .max_register = STM32_SPDIFRX_SIDR, 6598c2ecf20Sopenharmony_ci .readable_reg = stm32_spdifrx_readable_reg, 6608c2ecf20Sopenharmony_ci .volatile_reg = stm32_spdifrx_volatile_reg, 6618c2ecf20Sopenharmony_ci .writeable_reg = stm32_spdifrx_writeable_reg, 6628c2ecf20Sopenharmony_ci .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1, 6638c2ecf20Sopenharmony_ci .fast_io = true, 6648c2ecf20Sopenharmony_ci .cache_type = REGCACHE_FLAT, 6658c2ecf20Sopenharmony_ci}; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_cistatic irqreturn_t stm32_spdifrx_isr(int irq, void *devid) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; 6708c2ecf20Sopenharmony_ci struct platform_device *pdev = spdifrx->pdev; 6718c2ecf20Sopenharmony_ci unsigned int cr, mask, sr, imr; 6728c2ecf20Sopenharmony_ci unsigned int flags, sync_state; 6738c2ecf20Sopenharmony_ci int err = 0, err_xrun = 0; 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); 6768c2ecf20Sopenharmony_ci regmap_read(spdifrx->regmap, STM32_SPDIFRX_IMR, &imr); 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci mask = imr & SPDIFRX_XIMR_MASK; 6798c2ecf20Sopenharmony_ci /* SERR, TERR, FERR IRQs are generated if IFEIE is set */ 6808c2ecf20Sopenharmony_ci if (mask & SPDIFRX_IMR_IFEIE) 6818c2ecf20Sopenharmony_ci mask |= (SPDIFRX_IMR_IFEIE << 1) | (SPDIFRX_IMR_IFEIE << 2); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci flags = sr & mask; 6848c2ecf20Sopenharmony_ci if (!flags) { 6858c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Unexpected IRQ. rflags=%#x, imr=%#x\n", 6868c2ecf20Sopenharmony_ci sr, imr); 6878c2ecf20Sopenharmony_ci return IRQ_NONE; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci /* Clear IRQs */ 6918c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, 6928c2ecf20Sopenharmony_ci SPDIFRX_XIFCR_MASK, flags); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_PERR) { 6958c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Parity error\n"); 6968c2ecf20Sopenharmony_ci err_xrun = 1; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_OVR) { 7008c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Overrun error\n"); 7018c2ecf20Sopenharmony_ci err_xrun = 1; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_SBD) 7058c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Synchronization block detected\n"); 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_SYNCD) { 7088c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Synchronization done\n"); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* Enable spdifrx */ 7118c2ecf20Sopenharmony_ci cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_ENABLE); 7128c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 7138c2ecf20Sopenharmony_ci SPDIFRX_CR_SPDIFEN_MASK, cr); 7148c2ecf20Sopenharmony_ci } 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_FERR) { 7178c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Frame error\n"); 7188c2ecf20Sopenharmony_ci err = 1; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci 7218c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_SERR) { 7228c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Synchronization error\n"); 7238c2ecf20Sopenharmony_ci err = 1; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (flags & SPDIFRX_SR_TERR) { 7278c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "Timeout error\n"); 7288c2ecf20Sopenharmony_ci err = 1; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (err) { 7328c2ecf20Sopenharmony_ci regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); 7338c2ecf20Sopenharmony_ci sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) && 7348c2ecf20Sopenharmony_ci SPDIFRX_SPDIFEN_SYNC; 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_ci /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */ 7378c2ecf20Sopenharmony_ci cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); 7388c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 7398c2ecf20Sopenharmony_ci SPDIFRX_CR_SPDIFEN_MASK, cr); 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* If SPDIFRX was in STATE_SYNC, retry synchro */ 7428c2ecf20Sopenharmony_ci if (sync_state) { 7438c2ecf20Sopenharmony_ci cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); 7448c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 7458c2ecf20Sopenharmony_ci SPDIFRX_CR_SPDIFEN_MASK, cr); 7468c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci spin_lock(&spdifrx->irq_lock); 7508c2ecf20Sopenharmony_ci if (spdifrx->substream) 7518c2ecf20Sopenharmony_ci snd_pcm_stop(spdifrx->substream, 7528c2ecf20Sopenharmony_ci SNDRV_PCM_STATE_DISCONNECTED); 7538c2ecf20Sopenharmony_ci spin_unlock(&spdifrx->irq_lock); 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7568c2ecf20Sopenharmony_ci } 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci spin_lock(&spdifrx->irq_lock); 7598c2ecf20Sopenharmony_ci if (err_xrun && spdifrx->substream) 7608c2ecf20Sopenharmony_ci snd_pcm_stop_xrun(spdifrx->substream); 7618c2ecf20Sopenharmony_ci spin_unlock(&spdifrx->irq_lock); 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci return IRQ_HANDLED; 7648c2ecf20Sopenharmony_ci} 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_cistatic int stm32_spdifrx_startup(struct snd_pcm_substream *substream, 7678c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 7688c2ecf20Sopenharmony_ci{ 7698c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 7708c2ecf20Sopenharmony_ci unsigned long flags; 7718c2ecf20Sopenharmony_ci int ret; 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci spin_lock_irqsave(&spdifrx->irq_lock, flags); 7748c2ecf20Sopenharmony_ci spdifrx->substream = substream; 7758c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spdifrx->irq_lock, flags); 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci ret = clk_prepare_enable(spdifrx->kclk); 7788c2ecf20Sopenharmony_ci if (ret) 7798c2ecf20Sopenharmony_ci dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci return ret; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream, 7858c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 7868c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 7878c2ecf20Sopenharmony_ci{ 7888c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 7898c2ecf20Sopenharmony_ci int data_size = params_width(params); 7908c2ecf20Sopenharmony_ci int fmt; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci switch (data_size) { 7938c2ecf20Sopenharmony_ci case 16: 7948c2ecf20Sopenharmony_ci fmt = SPDIFRX_DRFMT_PACKED; 7958c2ecf20Sopenharmony_ci break; 7968c2ecf20Sopenharmony_ci case 32: 7978c2ecf20Sopenharmony_ci fmt = SPDIFRX_DRFMT_LEFT; 7988c2ecf20Sopenharmony_ci break; 7998c2ecf20Sopenharmony_ci default: 8008c2ecf20Sopenharmony_ci dev_err(&spdifrx->pdev->dev, "Unexpected data format\n"); 8018c2ecf20Sopenharmony_ci return -EINVAL; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci 8048c2ecf20Sopenharmony_ci /* 8058c2ecf20Sopenharmony_ci * Set buswidth to 4 bytes for all data formats. 8068c2ecf20Sopenharmony_ci * Packed format: transfer 2 x 2 bytes samples 8078c2ecf20Sopenharmony_ci * Left format: transfer 1 x 3 bytes samples + 1 dummy byte 8088c2ecf20Sopenharmony_ci */ 8098c2ecf20Sopenharmony_ci spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 8108c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 8138c2ecf20Sopenharmony_ci SPDIFRX_CR_DRFMT_MASK, 8148c2ecf20Sopenharmony_ci SPDIFRX_CR_DRFMTSET(fmt)); 8158c2ecf20Sopenharmony_ci} 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_cistatic int stm32_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd, 8188c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 8218c2ecf20Sopenharmony_ci int ret = 0; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci switch (cmd) { 8248c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 8258c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 8268c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 8278c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, 8288c2ecf20Sopenharmony_ci SPDIFRX_IMR_OVRIE, SPDIFRX_IMR_OVRIE); 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 8318c2ecf20Sopenharmony_ci SPDIFRX_CR_RXDMAEN, SPDIFRX_CR_RXDMAEN); 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ret = stm32_spdifrx_start_sync(spdifrx); 8348c2ecf20Sopenharmony_ci break; 8358c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 8368c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 8378c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 8388c2ecf20Sopenharmony_ci stm32_spdifrx_stop(spdifrx); 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci default: 8418c2ecf20Sopenharmony_ci return -EINVAL; 8428c2ecf20Sopenharmony_ci } 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci return ret; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_cistatic void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, 8488c2ecf20Sopenharmony_ci struct snd_soc_dai *cpu_dai) 8498c2ecf20Sopenharmony_ci{ 8508c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 8518c2ecf20Sopenharmony_ci unsigned long flags; 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci spin_lock_irqsave(&spdifrx->irq_lock, flags); 8548c2ecf20Sopenharmony_ci spdifrx->substream = NULL; 8558c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&spdifrx->irq_lock, flags); 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci clk_disable_unprepare(spdifrx->kclk); 8588c2ecf20Sopenharmony_ci} 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { 8618c2ecf20Sopenharmony_ci .startup = stm32_spdifrx_startup, 8628c2ecf20Sopenharmony_ci .hw_params = stm32_spdifrx_hw_params, 8638c2ecf20Sopenharmony_ci .trigger = stm32_spdifrx_trigger, 8648c2ecf20Sopenharmony_ci .shutdown = stm32_spdifrx_shutdown, 8658c2ecf20Sopenharmony_ci}; 8668c2ecf20Sopenharmony_ci 8678c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver stm32_spdifrx_dai[] = { 8688c2ecf20Sopenharmony_ci { 8698c2ecf20Sopenharmony_ci .probe = stm32_spdifrx_dai_probe, 8708c2ecf20Sopenharmony_ci .capture = { 8718c2ecf20Sopenharmony_ci .stream_name = "CPU-Capture", 8728c2ecf20Sopenharmony_ci .channels_min = 1, 8738c2ecf20Sopenharmony_ci .channels_max = 2, 8748c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_8000_192000, 8758c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE | 8768c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S16_LE, 8778c2ecf20Sopenharmony_ci }, 8788c2ecf20Sopenharmony_ci .ops = &stm32_spdifrx_pcm_dai_ops, 8798c2ecf20Sopenharmony_ci } 8808c2ecf20Sopenharmony_ci}; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { 8838c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, 8848c2ecf20Sopenharmony_ci .buffer_bytes_max = 8 * PAGE_SIZE, 8858c2ecf20Sopenharmony_ci .period_bytes_min = 1024, 8868c2ecf20Sopenharmony_ci .period_bytes_max = 4 * PAGE_SIZE, 8878c2ecf20Sopenharmony_ci .periods_min = 2, 8888c2ecf20Sopenharmony_ci .periods_max = 8, 8898c2ecf20Sopenharmony_ci}; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver stm32_spdifrx_component = { 8928c2ecf20Sopenharmony_ci .name = "stm32-spdifrx", 8938c2ecf20Sopenharmony_ci}; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config = { 8968c2ecf20Sopenharmony_ci .pcm_hardware = &stm32_spdifrx_pcm_hw, 8978c2ecf20Sopenharmony_ci .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 8988c2ecf20Sopenharmony_ci}; 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_cistatic const struct of_device_id stm32_spdifrx_ids[] = { 9018c2ecf20Sopenharmony_ci { 9028c2ecf20Sopenharmony_ci .compatible = "st,stm32h7-spdifrx", 9038c2ecf20Sopenharmony_ci .data = &stm32_h7_spdifrx_regmap_conf 9048c2ecf20Sopenharmony_ci }, 9058c2ecf20Sopenharmony_ci {} 9068c2ecf20Sopenharmony_ci}; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_cistatic int stm32_spdifrx_parse_of(struct platform_device *pdev, 9098c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 9128c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 9138c2ecf20Sopenharmony_ci struct resource *res; 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci if (!np) 9168c2ecf20Sopenharmony_ci return -ENODEV; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci of_id = of_match_device(stm32_spdifrx_ids, &pdev->dev); 9198c2ecf20Sopenharmony_ci if (of_id) 9208c2ecf20Sopenharmony_ci spdifrx->regmap_conf = 9218c2ecf20Sopenharmony_ci (const struct regmap_config *)of_id->data; 9228c2ecf20Sopenharmony_ci else 9238c2ecf20Sopenharmony_ci return -EINVAL; 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 9268c2ecf20Sopenharmony_ci spdifrx->base = devm_ioremap_resource(&pdev->dev, res); 9278c2ecf20Sopenharmony_ci if (IS_ERR(spdifrx->base)) 9288c2ecf20Sopenharmony_ci return PTR_ERR(spdifrx->base); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci spdifrx->phys_addr = res->start; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); 9338c2ecf20Sopenharmony_ci if (IS_ERR(spdifrx->kclk)) { 9348c2ecf20Sopenharmony_ci if (PTR_ERR(spdifrx->kclk) != -EPROBE_DEFER) 9358c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Could not get kclk: %ld\n", 9368c2ecf20Sopenharmony_ci PTR_ERR(spdifrx->kclk)); 9378c2ecf20Sopenharmony_ci return PTR_ERR(spdifrx->kclk); 9388c2ecf20Sopenharmony_ci } 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci spdifrx->irq = platform_get_irq(pdev, 0); 9418c2ecf20Sopenharmony_ci if (spdifrx->irq < 0) 9428c2ecf20Sopenharmony_ci return spdifrx->irq; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int stm32_spdifrx_remove(struct platform_device *pdev) 9488c2ecf20Sopenharmony_ci{ 9498c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if (spdifrx->ctrl_chan) 9528c2ecf20Sopenharmony_ci dma_release_channel(spdifrx->ctrl_chan); 9538c2ecf20Sopenharmony_ci 9548c2ecf20Sopenharmony_ci if (spdifrx->dmab) 9558c2ecf20Sopenharmony_ci snd_dma_free_pages(spdifrx->dmab); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci snd_dmaengine_pcm_unregister(&pdev->dev); 9588c2ecf20Sopenharmony_ci snd_soc_unregister_component(&pdev->dev); 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci return 0; 9618c2ecf20Sopenharmony_ci} 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_cistatic int stm32_spdifrx_probe(struct platform_device *pdev) 9648c2ecf20Sopenharmony_ci{ 9658c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx; 9668c2ecf20Sopenharmony_ci struct reset_control *rst; 9678c2ecf20Sopenharmony_ci const struct snd_dmaengine_pcm_config *pcm_config = NULL; 9688c2ecf20Sopenharmony_ci u32 ver, idr; 9698c2ecf20Sopenharmony_ci int ret; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); 9728c2ecf20Sopenharmony_ci if (!spdifrx) 9738c2ecf20Sopenharmony_ci return -ENOMEM; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci spdifrx->pdev = pdev; 9768c2ecf20Sopenharmony_ci init_completion(&spdifrx->cs_completion); 9778c2ecf20Sopenharmony_ci spin_lock_init(&spdifrx->lock); 9788c2ecf20Sopenharmony_ci spin_lock_init(&spdifrx->irq_lock); 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, spdifrx); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci ret = stm32_spdifrx_parse_of(pdev, spdifrx); 9838c2ecf20Sopenharmony_ci if (ret) 9848c2ecf20Sopenharmony_ci return ret; 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", 9878c2ecf20Sopenharmony_ci spdifrx->base, 9888c2ecf20Sopenharmony_ci spdifrx->regmap_conf); 9898c2ecf20Sopenharmony_ci if (IS_ERR(spdifrx->regmap)) { 9908c2ecf20Sopenharmony_ci if (PTR_ERR(spdifrx->regmap) != -EPROBE_DEFER) 9918c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Regmap init error %ld\n", 9928c2ecf20Sopenharmony_ci PTR_ERR(spdifrx->regmap)); 9938c2ecf20Sopenharmony_ci return PTR_ERR(spdifrx->regmap); 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, 9978c2ecf20Sopenharmony_ci dev_name(&pdev->dev), spdifrx); 9988c2ecf20Sopenharmony_ci if (ret) { 9998c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "IRQ request returned %d\n", ret); 10008c2ecf20Sopenharmony_ci return ret; 10018c2ecf20Sopenharmony_ci } 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); 10048c2ecf20Sopenharmony_ci if (IS_ERR(rst)) { 10058c2ecf20Sopenharmony_ci if (PTR_ERR(rst) != -EPROBE_DEFER) 10068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "Reset controller error %ld\n", 10078c2ecf20Sopenharmony_ci PTR_ERR(rst)); 10088c2ecf20Sopenharmony_ci return PTR_ERR(rst); 10098c2ecf20Sopenharmony_ci } 10108c2ecf20Sopenharmony_ci reset_control_assert(rst); 10118c2ecf20Sopenharmony_ci udelay(2); 10128c2ecf20Sopenharmony_ci reset_control_deassert(rst); 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci pcm_config = &stm32_spdifrx_pcm_config; 10158c2ecf20Sopenharmony_ci ret = snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); 10168c2ecf20Sopenharmony_ci if (ret) { 10178c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 10188c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PCM DMA register error %d\n", ret); 10198c2ecf20Sopenharmony_ci return ret; 10208c2ecf20Sopenharmony_ci } 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_ci ret = snd_soc_register_component(&pdev->dev, 10238c2ecf20Sopenharmony_ci &stm32_spdifrx_component, 10248c2ecf20Sopenharmony_ci stm32_spdifrx_dai, 10258c2ecf20Sopenharmony_ci ARRAY_SIZE(stm32_spdifrx_dai)); 10268c2ecf20Sopenharmony_ci if (ret) { 10278c2ecf20Sopenharmony_ci snd_dmaengine_pcm_unregister(&pdev->dev); 10288c2ecf20Sopenharmony_ci return ret; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci ret = stm32_spdifrx_dma_ctrl_register(&pdev->dev, spdifrx); 10328c2ecf20Sopenharmony_ci if (ret) 10338c2ecf20Sopenharmony_ci goto error; 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr); 10368c2ecf20Sopenharmony_ci if (ret) 10378c2ecf20Sopenharmony_ci goto error; 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_ci if (idr == SPDIFRX_IPIDR_NUMBER) { 10408c2ecf20Sopenharmony_ci ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver); 10418c2ecf20Sopenharmony_ci if (ret) 10428c2ecf20Sopenharmony_ci goto error; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n", 10458c2ecf20Sopenharmony_ci FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver), 10468c2ecf20Sopenharmony_ci FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); 10478c2ecf20Sopenharmony_ci } 10488c2ecf20Sopenharmony_ci 10498c2ecf20Sopenharmony_ci return ret; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_cierror: 10528c2ecf20Sopenharmony_ci stm32_spdifrx_remove(pdev); 10538c2ecf20Sopenharmony_ci 10548c2ecf20Sopenharmony_ci return ret; 10558c2ecf20Sopenharmony_ci} 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 10608c2ecf20Sopenharmony_cistatic int stm32_spdifrx_suspend(struct device *dev) 10618c2ecf20Sopenharmony_ci{ 10628c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci regcache_cache_only(spdifrx->regmap, true); 10658c2ecf20Sopenharmony_ci regcache_mark_dirty(spdifrx->regmap); 10668c2ecf20Sopenharmony_ci 10678c2ecf20Sopenharmony_ci return 0; 10688c2ecf20Sopenharmony_ci} 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_cistatic int stm32_spdifrx_resume(struct device *dev) 10718c2ecf20Sopenharmony_ci{ 10728c2ecf20Sopenharmony_ci struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci regcache_cache_only(spdifrx->regmap, false); 10758c2ecf20Sopenharmony_ci 10768c2ecf20Sopenharmony_ci return regcache_sync(spdifrx->regmap); 10778c2ecf20Sopenharmony_ci} 10788c2ecf20Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_cistatic const struct dev_pm_ops stm32_spdifrx_pm_ops = { 10818c2ecf20Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume) 10828c2ecf20Sopenharmony_ci}; 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_cistatic struct platform_driver stm32_spdifrx_driver = { 10858c2ecf20Sopenharmony_ci .driver = { 10868c2ecf20Sopenharmony_ci .name = "st,stm32-spdifrx", 10878c2ecf20Sopenharmony_ci .of_match_table = stm32_spdifrx_ids, 10888c2ecf20Sopenharmony_ci .pm = &stm32_spdifrx_pm_ops, 10898c2ecf20Sopenharmony_ci }, 10908c2ecf20Sopenharmony_ci .probe = stm32_spdifrx_probe, 10918c2ecf20Sopenharmony_ci .remove = stm32_spdifrx_remove, 10928c2ecf20Sopenharmony_ci}; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cimodule_platform_driver(stm32_spdifrx_driver); 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("STM32 Soc spdifrx Interface"); 10978c2ecf20Sopenharmony_ciMODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>"); 10988c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:stm32-spdifrx"); 10998c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1100