11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 203e4d5d5Solivier moysan /* 303e4d5d5Solivier moysan * STM32 ALSA SoC Digital Audio Interface (SPDIF-rx) driver. 403e4d5d5Solivier moysan * 503e4d5d5Solivier moysan * Copyright (C) 2017, STMicroelectronics - All Rights Reserved 603e4d5d5Solivier moysan * Author(s): Olivier Moysan <olivier.moysan@st.com> for STMicroelectronics. 703e4d5d5Solivier moysan */ 803e4d5d5Solivier moysan 91a5c0b28SOlivier Moysan #include <linux/bitfield.h> 1003e4d5d5Solivier moysan #include <linux/clk.h> 1103e4d5d5Solivier moysan #include <linux/completion.h> 1203e4d5d5Solivier moysan #include <linux/delay.h> 1303e4d5d5Solivier moysan #include <linux/module.h> 1403e4d5d5Solivier moysan #include <linux/of_platform.h> 15f68c2a68SOlivier Moysan #include <linux/pinctrl/consumer.h> 1603e4d5d5Solivier moysan #include <linux/regmap.h> 1703e4d5d5Solivier moysan #include <linux/reset.h> 1803e4d5d5Solivier moysan 1903e4d5d5Solivier moysan #include <sound/dmaengine_pcm.h> 2003e4d5d5Solivier moysan #include <sound/pcm_params.h> 2103e4d5d5Solivier moysan 2203e4d5d5Solivier moysan /* SPDIF-rx Register Map */ 2303e4d5d5Solivier moysan #define STM32_SPDIFRX_CR 0x00 2403e4d5d5Solivier moysan #define STM32_SPDIFRX_IMR 0x04 2503e4d5d5Solivier moysan #define STM32_SPDIFRX_SR 0x08 2603e4d5d5Solivier moysan #define STM32_SPDIFRX_IFCR 0x0C 2703e4d5d5Solivier moysan #define STM32_SPDIFRX_DR 0x10 2803e4d5d5Solivier moysan #define STM32_SPDIFRX_CSR 0x14 2903e4d5d5Solivier moysan #define STM32_SPDIFRX_DIR 0x18 301a5c0b28SOlivier Moysan #define STM32_SPDIFRX_VERR 0x3F4 311a5c0b28SOlivier Moysan #define STM32_SPDIFRX_IDR 0x3F8 321a5c0b28SOlivier Moysan #define STM32_SPDIFRX_SIDR 0x3FC 3303e4d5d5Solivier moysan 3403e4d5d5Solivier moysan /* Bit definition for SPDIF_CR register */ 3503e4d5d5Solivier moysan #define SPDIFRX_CR_SPDIFEN_SHIFT 0 3603e4d5d5Solivier moysan #define SPDIFRX_CR_SPDIFEN_MASK GENMASK(1, SPDIFRX_CR_SPDIFEN_SHIFT) 3703e4d5d5Solivier moysan #define SPDIFRX_CR_SPDIFENSET(x) ((x) << SPDIFRX_CR_SPDIFEN_SHIFT) 3803e4d5d5Solivier moysan 3903e4d5d5Solivier moysan #define SPDIFRX_CR_RXDMAEN BIT(2) 4003e4d5d5Solivier moysan #define SPDIFRX_CR_RXSTEO BIT(3) 4103e4d5d5Solivier moysan 4203e4d5d5Solivier moysan #define SPDIFRX_CR_DRFMT_SHIFT 4 4303e4d5d5Solivier moysan #define SPDIFRX_CR_DRFMT_MASK GENMASK(5, SPDIFRX_CR_DRFMT_SHIFT) 4403e4d5d5Solivier moysan #define SPDIFRX_CR_DRFMTSET(x) ((x) << SPDIFRX_CR_DRFMT_SHIFT) 4503e4d5d5Solivier moysan 4603e4d5d5Solivier moysan #define SPDIFRX_CR_PMSK BIT(6) 4703e4d5d5Solivier moysan #define SPDIFRX_CR_VMSK BIT(7) 4803e4d5d5Solivier moysan #define SPDIFRX_CR_CUMSK BIT(8) 4903e4d5d5Solivier moysan #define SPDIFRX_CR_PTMSK BIT(9) 5003e4d5d5Solivier moysan #define SPDIFRX_CR_CBDMAEN BIT(10) 5103e4d5d5Solivier moysan #define SPDIFRX_CR_CHSEL_SHIFT 11 5203e4d5d5Solivier moysan #define SPDIFRX_CR_CHSEL BIT(SPDIFRX_CR_CHSEL_SHIFT) 5303e4d5d5Solivier moysan 5403e4d5d5Solivier moysan #define SPDIFRX_CR_NBTR_SHIFT 12 5503e4d5d5Solivier moysan #define SPDIFRX_CR_NBTR_MASK GENMASK(13, SPDIFRX_CR_NBTR_SHIFT) 5603e4d5d5Solivier moysan #define SPDIFRX_CR_NBTRSET(x) ((x) << SPDIFRX_CR_NBTR_SHIFT) 5703e4d5d5Solivier moysan 5803e4d5d5Solivier moysan #define SPDIFRX_CR_WFA BIT(14) 5903e4d5d5Solivier moysan 6003e4d5d5Solivier moysan #define SPDIFRX_CR_INSEL_SHIFT 16 6103e4d5d5Solivier moysan #define SPDIFRX_CR_INSEL_MASK GENMASK(18, PDIFRX_CR_INSEL_SHIFT) 6203e4d5d5Solivier moysan #define SPDIFRX_CR_INSELSET(x) ((x) << SPDIFRX_CR_INSEL_SHIFT) 6303e4d5d5Solivier moysan 6403e4d5d5Solivier moysan #define SPDIFRX_CR_CKSEN_SHIFT 20 6503e4d5d5Solivier moysan #define SPDIFRX_CR_CKSEN BIT(20) 6603e4d5d5Solivier moysan #define SPDIFRX_CR_CKSBKPEN BIT(21) 6703e4d5d5Solivier moysan 6803e4d5d5Solivier moysan /* Bit definition for SPDIFRX_IMR register */ 6903e4d5d5Solivier moysan #define SPDIFRX_IMR_RXNEI BIT(0) 7003e4d5d5Solivier moysan #define SPDIFRX_IMR_CSRNEIE BIT(1) 7103e4d5d5Solivier moysan #define SPDIFRX_IMR_PERRIE BIT(2) 7203e4d5d5Solivier moysan #define SPDIFRX_IMR_OVRIE BIT(3) 7303e4d5d5Solivier moysan #define SPDIFRX_IMR_SBLKIE BIT(4) 7403e4d5d5Solivier moysan #define SPDIFRX_IMR_SYNCDIE BIT(5) 7503e4d5d5Solivier moysan #define SPDIFRX_IMR_IFEIE BIT(6) 7603e4d5d5Solivier moysan 7703e4d5d5Solivier moysan #define SPDIFRX_XIMR_MASK GENMASK(6, 0) 7803e4d5d5Solivier moysan 7903e4d5d5Solivier moysan /* Bit definition for SPDIFRX_SR register */ 8003e4d5d5Solivier moysan #define SPDIFRX_SR_RXNE BIT(0) 8103e4d5d5Solivier moysan #define SPDIFRX_SR_CSRNE BIT(1) 8203e4d5d5Solivier moysan #define SPDIFRX_SR_PERR BIT(2) 8303e4d5d5Solivier moysan #define SPDIFRX_SR_OVR BIT(3) 8403e4d5d5Solivier moysan #define SPDIFRX_SR_SBD BIT(4) 8503e4d5d5Solivier moysan #define SPDIFRX_SR_SYNCD BIT(5) 8603e4d5d5Solivier moysan #define SPDIFRX_SR_FERR BIT(6) 8703e4d5d5Solivier moysan #define SPDIFRX_SR_SERR BIT(7) 8803e4d5d5Solivier moysan #define SPDIFRX_SR_TERR BIT(8) 8903e4d5d5Solivier moysan 9003e4d5d5Solivier moysan #define SPDIFRX_SR_WIDTH5_SHIFT 16 9103e4d5d5Solivier moysan #define SPDIFRX_SR_WIDTH5_MASK GENMASK(30, PDIFRX_SR_WIDTH5_SHIFT) 9203e4d5d5Solivier moysan #define SPDIFRX_SR_WIDTH5SET(x) ((x) << SPDIFRX_SR_WIDTH5_SHIFT) 9303e4d5d5Solivier moysan 9403e4d5d5Solivier moysan /* Bit definition for SPDIFRX_IFCR register */ 9503e4d5d5Solivier moysan #define SPDIFRX_IFCR_PERRCF BIT(2) 9603e4d5d5Solivier moysan #define SPDIFRX_IFCR_OVRCF BIT(3) 9703e4d5d5Solivier moysan #define SPDIFRX_IFCR_SBDCF BIT(4) 9803e4d5d5Solivier moysan #define SPDIFRX_IFCR_SYNCDCF BIT(5) 9903e4d5d5Solivier moysan 10003e4d5d5Solivier moysan #define SPDIFRX_XIFCR_MASK GENMASK(5, 2) 10103e4d5d5Solivier moysan 10203e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DR register (DRFMT = 0b00) */ 10303e4d5d5Solivier moysan #define SPDIFRX_DR0_DR_SHIFT 0 10403e4d5d5Solivier moysan #define SPDIFRX_DR0_DR_MASK GENMASK(23, SPDIFRX_DR0_DR_SHIFT) 10503e4d5d5Solivier moysan #define SPDIFRX_DR0_DRSET(x) ((x) << SPDIFRX_DR0_DR_SHIFT) 10603e4d5d5Solivier moysan 10703e4d5d5Solivier moysan #define SPDIFRX_DR0_PE BIT(24) 10803e4d5d5Solivier moysan 10903e4d5d5Solivier moysan #define SPDIFRX_DR0_V BIT(25) 11003e4d5d5Solivier moysan #define SPDIFRX_DR0_U BIT(26) 11103e4d5d5Solivier moysan #define SPDIFRX_DR0_C BIT(27) 11203e4d5d5Solivier moysan 11303e4d5d5Solivier moysan #define SPDIFRX_DR0_PT_SHIFT 28 11403e4d5d5Solivier moysan #define SPDIFRX_DR0_PT_MASK GENMASK(29, SPDIFRX_DR0_PT_SHIFT) 11503e4d5d5Solivier moysan #define SPDIFRX_DR0_PTSET(x) ((x) << SPDIFRX_DR0_PT_SHIFT) 11603e4d5d5Solivier moysan 11703e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DR register (DRFMT = 0b01) */ 11803e4d5d5Solivier moysan #define SPDIFRX_DR1_PE BIT(0) 11903e4d5d5Solivier moysan #define SPDIFRX_DR1_V BIT(1) 12003e4d5d5Solivier moysan #define SPDIFRX_DR1_U BIT(2) 12103e4d5d5Solivier moysan #define SPDIFRX_DR1_C BIT(3) 12203e4d5d5Solivier moysan 12303e4d5d5Solivier moysan #define SPDIFRX_DR1_PT_SHIFT 4 12403e4d5d5Solivier moysan #define SPDIFRX_DR1_PT_MASK GENMASK(5, SPDIFRX_DR1_PT_SHIFT) 12503e4d5d5Solivier moysan #define SPDIFRX_DR1_PTSET(x) ((x) << SPDIFRX_DR1_PT_SHIFT) 12603e4d5d5Solivier moysan 12703e4d5d5Solivier moysan #define SPDIFRX_DR1_DR_SHIFT 8 12803e4d5d5Solivier moysan #define SPDIFRX_DR1_DR_MASK GENMASK(31, SPDIFRX_DR1_DR_SHIFT) 12903e4d5d5Solivier moysan #define SPDIFRX_DR1_DRSET(x) ((x) << SPDIFRX_DR1_DR_SHIFT) 13003e4d5d5Solivier moysan 13103e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DR register (DRFMT = 0b10) */ 13203e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL1_SHIFT 0 13303e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL1_MASK GENMASK(15, SPDIFRX_DR1_DRNL1_SHIFT) 13403e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL1SET(x) ((x) << SPDIFRX_DR1_DRNL1_SHIFT) 13503e4d5d5Solivier moysan 13603e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL2_SHIFT 16 13703e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL2_MASK GENMASK(31, SPDIFRX_DR1_DRNL2_SHIFT) 13803e4d5d5Solivier moysan #define SPDIFRX_DR1_DRNL2SET(x) ((x) << SPDIFRX_DR1_DRNL2_SHIFT) 13903e4d5d5Solivier moysan 14003e4d5d5Solivier moysan /* Bit definition for SPDIFRX_CSR register */ 14103e4d5d5Solivier moysan #define SPDIFRX_CSR_USR_SHIFT 0 14203e4d5d5Solivier moysan #define SPDIFRX_CSR_USR_MASK GENMASK(15, SPDIFRX_CSR_USR_SHIFT) 14303e4d5d5Solivier moysan #define SPDIFRX_CSR_USRGET(x) (((x) & SPDIFRX_CSR_USR_MASK)\ 14403e4d5d5Solivier moysan >> SPDIFRX_CSR_USR_SHIFT) 14503e4d5d5Solivier moysan 14603e4d5d5Solivier moysan #define SPDIFRX_CSR_CS_SHIFT 16 14703e4d5d5Solivier moysan #define SPDIFRX_CSR_CS_MASK GENMASK(23, SPDIFRX_CSR_CS_SHIFT) 14803e4d5d5Solivier moysan #define SPDIFRX_CSR_CSGET(x) (((x) & SPDIFRX_CSR_CS_MASK)\ 14903e4d5d5Solivier moysan >> SPDIFRX_CSR_CS_SHIFT) 15003e4d5d5Solivier moysan 15103e4d5d5Solivier moysan #define SPDIFRX_CSR_SOB BIT(24) 15203e4d5d5Solivier moysan 15303e4d5d5Solivier moysan /* Bit definition for SPDIFRX_DIR register */ 15403e4d5d5Solivier moysan #define SPDIFRX_DIR_THI_SHIFT 0 15503e4d5d5Solivier moysan #define SPDIFRX_DIR_THI_MASK GENMASK(12, SPDIFRX_DIR_THI_SHIFT) 15603e4d5d5Solivier moysan #define SPDIFRX_DIR_THI_SET(x) ((x) << SPDIFRX_DIR_THI_SHIFT) 15703e4d5d5Solivier moysan 15803e4d5d5Solivier moysan #define SPDIFRX_DIR_TLO_SHIFT 16 15903e4d5d5Solivier moysan #define SPDIFRX_DIR_TLO_MASK GENMASK(28, SPDIFRX_DIR_TLO_SHIFT) 16003e4d5d5Solivier moysan #define SPDIFRX_DIR_TLO_SET(x) ((x) << SPDIFRX_DIR_TLO_SHIFT) 16103e4d5d5Solivier moysan 16203e4d5d5Solivier moysan #define SPDIFRX_SPDIFEN_DISABLE 0x0 16303e4d5d5Solivier moysan #define SPDIFRX_SPDIFEN_SYNC 0x1 16403e4d5d5Solivier moysan #define SPDIFRX_SPDIFEN_ENABLE 0x3 16503e4d5d5Solivier moysan 1661a5c0b28SOlivier Moysan /* Bit definition for SPDIFRX_VERR register */ 1671a5c0b28SOlivier Moysan #define SPDIFRX_VERR_MIN_MASK GENMASK(3, 0) 1681a5c0b28SOlivier Moysan #define SPDIFRX_VERR_MAJ_MASK GENMASK(7, 4) 1691a5c0b28SOlivier Moysan 1701a5c0b28SOlivier Moysan /* Bit definition for SPDIFRX_IDR register */ 1711a5c0b28SOlivier Moysan #define SPDIFRX_IDR_ID_MASK GENMASK(31, 0) 1721a5c0b28SOlivier Moysan 1731a5c0b28SOlivier Moysan /* Bit definition for SPDIFRX_SIDR register */ 1741a5c0b28SOlivier Moysan #define SPDIFRX_SIDR_SID_MASK GENMASK(31, 0) 1751a5c0b28SOlivier Moysan 1761a5c0b28SOlivier Moysan #define SPDIFRX_IPIDR_NUMBER 0x00130041 1771a5c0b28SOlivier Moysan 17803e4d5d5Solivier moysan #define SPDIFRX_IN1 0x1 17903e4d5d5Solivier moysan #define SPDIFRX_IN2 0x2 18003e4d5d5Solivier moysan #define SPDIFRX_IN3 0x3 18103e4d5d5Solivier moysan #define SPDIFRX_IN4 0x4 18203e4d5d5Solivier moysan #define SPDIFRX_IN5 0x5 18303e4d5d5Solivier moysan #define SPDIFRX_IN6 0x6 18403e4d5d5Solivier moysan #define SPDIFRX_IN7 0x7 18503e4d5d5Solivier moysan #define SPDIFRX_IN8 0x8 18603e4d5d5Solivier moysan 18703e4d5d5Solivier moysan #define SPDIFRX_NBTR_NONE 0x0 18803e4d5d5Solivier moysan #define SPDIFRX_NBTR_3 0x1 18903e4d5d5Solivier moysan #define SPDIFRX_NBTR_15 0x2 19003e4d5d5Solivier moysan #define SPDIFRX_NBTR_63 0x3 19103e4d5d5Solivier moysan 19203e4d5d5Solivier moysan #define SPDIFRX_DRFMT_RIGHT 0x0 19303e4d5d5Solivier moysan #define SPDIFRX_DRFMT_LEFT 0x1 19403e4d5d5Solivier moysan #define SPDIFRX_DRFMT_PACKED 0x2 19503e4d5d5Solivier moysan 19603e4d5d5Solivier moysan /* 192 CS bits in S/PDIF frame. i.e 24 CS bytes */ 19703e4d5d5Solivier moysan #define SPDIFRX_CS_BYTES_NB 24 19803e4d5d5Solivier moysan #define SPDIFRX_UB_BYTES_NB 48 19903e4d5d5Solivier moysan 20003e4d5d5Solivier moysan /* 20103e4d5d5Solivier moysan * CSR register is retrieved as a 32 bits word 20203e4d5d5Solivier moysan * It contains 1 channel status byte and 2 user data bytes 20303e4d5d5Solivier moysan * 2 S/PDIF frames are acquired to get all CS/UB bits 20403e4d5d5Solivier moysan */ 20503e4d5d5Solivier moysan #define SPDIFRX_CSR_BUF_LENGTH (SPDIFRX_CS_BYTES_NB * 4 * 2) 20603e4d5d5Solivier moysan 20703e4d5d5Solivier moysan /** 20803e4d5d5Solivier moysan * struct stm32_spdifrx_data - private data of SPDIFRX 20903e4d5d5Solivier moysan * @pdev: device data pointer 21003e4d5d5Solivier moysan * @base: mmio register base virtual address 21103e4d5d5Solivier moysan * @regmap: SPDIFRX register map pointer 21203e4d5d5Solivier moysan * @regmap_conf: SPDIFRX register map configuration pointer 21303e4d5d5Solivier moysan * @cs_completion: channel status retrieving completion 21403e4d5d5Solivier moysan * @kclk: kernel clock feeding the SPDIFRX clock generator 21503e4d5d5Solivier moysan * @dma_params: dma configuration data for rx channel 21603e4d5d5Solivier moysan * @substream: PCM substream data pointer 21703e4d5d5Solivier moysan * @dmab: dma buffer info pointer 21803e4d5d5Solivier moysan * @ctrl_chan: dma channel for S/PDIF control bits 21903e4d5d5Solivier moysan * @desc:dma async transaction descriptor 22003e4d5d5Solivier moysan * @slave_config: dma slave channel runtime config pointer 22103e4d5d5Solivier moysan * @phys_addr: SPDIFRX registers physical base address 22203e4d5d5Solivier moysan * @lock: synchronization enabling lock 223*86e1956aSOlivier Moysan * @irq_lock: prevent race condition with IRQ on stream state 22403e4d5d5Solivier moysan * @cs: channel status buffer 22503e4d5d5Solivier moysan * @ub: user data buffer 22603e4d5d5Solivier moysan * @irq: SPDIFRX interrupt line 22703e4d5d5Solivier moysan * @refcount: keep count of opened DMA channels 22803e4d5d5Solivier moysan */ 22903e4d5d5Solivier moysan struct stm32_spdifrx_data { 23003e4d5d5Solivier moysan struct platform_device *pdev; 23103e4d5d5Solivier moysan void __iomem *base; 23203e4d5d5Solivier moysan struct regmap *regmap; 23303e4d5d5Solivier moysan const struct regmap_config *regmap_conf; 23403e4d5d5Solivier moysan struct completion cs_completion; 23503e4d5d5Solivier moysan struct clk *kclk; 23603e4d5d5Solivier moysan struct snd_dmaengine_dai_dma_data dma_params; 23703e4d5d5Solivier moysan struct snd_pcm_substream *substream; 23803e4d5d5Solivier moysan struct snd_dma_buffer *dmab; 23903e4d5d5Solivier moysan struct dma_chan *ctrl_chan; 24003e4d5d5Solivier moysan struct dma_async_tx_descriptor *desc; 24103e4d5d5Solivier moysan struct dma_slave_config slave_config; 24203e4d5d5Solivier moysan dma_addr_t phys_addr; 24303e4d5d5Solivier moysan spinlock_t lock; /* Sync enabling lock */ 244*86e1956aSOlivier Moysan spinlock_t irq_lock; /* Prevent race condition on stream state */ 24503e4d5d5Solivier moysan unsigned char cs[SPDIFRX_CS_BYTES_NB]; 24603e4d5d5Solivier moysan unsigned char ub[SPDIFRX_UB_BYTES_NB]; 24703e4d5d5Solivier moysan int irq; 24803e4d5d5Solivier moysan int refcount; 24903e4d5d5Solivier moysan }; 25003e4d5d5Solivier moysan 25103e4d5d5Solivier moysan static void stm32_spdifrx_dma_complete(void *data) 25203e4d5d5Solivier moysan { 25303e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)data; 25403e4d5d5Solivier moysan struct platform_device *pdev = spdifrx->pdev; 25503e4d5d5Solivier moysan u32 *p_start = (u32 *)spdifrx->dmab->area; 25603e4d5d5Solivier moysan u32 *p_end = p_start + (2 * SPDIFRX_CS_BYTES_NB) - 1; 25703e4d5d5Solivier moysan u32 *ptr = p_start; 25803e4d5d5Solivier moysan u16 *ub_ptr = (short *)spdifrx->ub; 25903e4d5d5Solivier moysan int i = 0; 26003e4d5d5Solivier moysan 26103e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 26203e4d5d5Solivier moysan SPDIFRX_CR_CBDMAEN, 26303e4d5d5Solivier moysan (unsigned int)~SPDIFRX_CR_CBDMAEN); 26403e4d5d5Solivier moysan 26503e4d5d5Solivier moysan if (!spdifrx->dmab->area) 26603e4d5d5Solivier moysan return; 26703e4d5d5Solivier moysan 26803e4d5d5Solivier moysan while (ptr <= p_end) { 26903e4d5d5Solivier moysan if (*ptr & SPDIFRX_CSR_SOB) 27003e4d5d5Solivier moysan break; 27103e4d5d5Solivier moysan ptr++; 27203e4d5d5Solivier moysan } 27303e4d5d5Solivier moysan 27403e4d5d5Solivier moysan if (ptr > p_end) { 27503e4d5d5Solivier moysan dev_err(&pdev->dev, "Start of S/PDIF block not found\n"); 27603e4d5d5Solivier moysan return; 27703e4d5d5Solivier moysan } 27803e4d5d5Solivier moysan 27903e4d5d5Solivier moysan while (i < SPDIFRX_CS_BYTES_NB) { 28003e4d5d5Solivier moysan spdifrx->cs[i] = (unsigned char)SPDIFRX_CSR_CSGET(*ptr); 28103e4d5d5Solivier moysan *ub_ptr++ = SPDIFRX_CSR_USRGET(*ptr++); 28203e4d5d5Solivier moysan if (ptr > p_end) { 28303e4d5d5Solivier moysan dev_err(&pdev->dev, "Failed to get channel status\n"); 28403e4d5d5Solivier moysan return; 28503e4d5d5Solivier moysan } 28603e4d5d5Solivier moysan i++; 28703e4d5d5Solivier moysan } 28803e4d5d5Solivier moysan 28903e4d5d5Solivier moysan complete(&spdifrx->cs_completion); 29003e4d5d5Solivier moysan } 29103e4d5d5Solivier moysan 29203e4d5d5Solivier moysan static int stm32_spdifrx_dma_ctrl_start(struct stm32_spdifrx_data *spdifrx) 29303e4d5d5Solivier moysan { 29403e4d5d5Solivier moysan dma_cookie_t cookie; 29503e4d5d5Solivier moysan int err; 29603e4d5d5Solivier moysan 29703e4d5d5Solivier moysan spdifrx->desc = dmaengine_prep_slave_single(spdifrx->ctrl_chan, 29803e4d5d5Solivier moysan spdifrx->dmab->addr, 29903e4d5d5Solivier moysan SPDIFRX_CSR_BUF_LENGTH, 30003e4d5d5Solivier moysan DMA_DEV_TO_MEM, 30103e4d5d5Solivier moysan DMA_CTRL_ACK); 30203e4d5d5Solivier moysan if (!spdifrx->desc) 30303e4d5d5Solivier moysan return -EINVAL; 30403e4d5d5Solivier moysan 30503e4d5d5Solivier moysan spdifrx->desc->callback = stm32_spdifrx_dma_complete; 30603e4d5d5Solivier moysan spdifrx->desc->callback_param = spdifrx; 30703e4d5d5Solivier moysan cookie = dmaengine_submit(spdifrx->desc); 30803e4d5d5Solivier moysan err = dma_submit_error(cookie); 30903e4d5d5Solivier moysan if (err) 31003e4d5d5Solivier moysan return -EINVAL; 31103e4d5d5Solivier moysan 31203e4d5d5Solivier moysan dma_async_issue_pending(spdifrx->ctrl_chan); 31303e4d5d5Solivier moysan 31403e4d5d5Solivier moysan return 0; 31503e4d5d5Solivier moysan } 31603e4d5d5Solivier moysan 31703e4d5d5Solivier moysan static void stm32_spdifrx_dma_ctrl_stop(struct stm32_spdifrx_data *spdifrx) 31803e4d5d5Solivier moysan { 31903e4d5d5Solivier moysan dmaengine_terminate_async(spdifrx->ctrl_chan); 32003e4d5d5Solivier moysan } 32103e4d5d5Solivier moysan 32203e4d5d5Solivier moysan static int stm32_spdifrx_start_sync(struct stm32_spdifrx_data *spdifrx) 32303e4d5d5Solivier moysan { 32403e4d5d5Solivier moysan int cr, cr_mask, imr, ret; 3252859b178SOlivier Moysan unsigned long flags; 32603e4d5d5Solivier moysan 32703e4d5d5Solivier moysan /* Enable IRQs */ 32803e4d5d5Solivier moysan imr = SPDIFRX_IMR_IFEIE | SPDIFRX_IMR_SYNCDIE | SPDIFRX_IMR_PERRIE; 32903e4d5d5Solivier moysan ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, imr, imr); 33003e4d5d5Solivier moysan if (ret) 33103e4d5d5Solivier moysan return ret; 33203e4d5d5Solivier moysan 3332859b178SOlivier Moysan spin_lock_irqsave(&spdifrx->lock, flags); 33403e4d5d5Solivier moysan 33503e4d5d5Solivier moysan spdifrx->refcount++; 33603e4d5d5Solivier moysan 33703e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); 33803e4d5d5Solivier moysan 33903e4d5d5Solivier moysan if (!(cr & SPDIFRX_CR_SPDIFEN_MASK)) { 34003e4d5d5Solivier moysan /* 34103e4d5d5Solivier moysan * Start sync if SPDIFRX is still in idle state. 34203e4d5d5Solivier moysan * SPDIFRX reception enabled when sync done 34303e4d5d5Solivier moysan */ 34403e4d5d5Solivier moysan dev_dbg(&spdifrx->pdev->dev, "start synchronization\n"); 34503e4d5d5Solivier moysan 34603e4d5d5Solivier moysan /* 34703e4d5d5Solivier moysan * SPDIFRX configuration: 34803e4d5d5Solivier moysan * Wait for activity before starting sync process. This avoid 34903e4d5d5Solivier moysan * to issue sync errors when spdif signal is missing on input. 35003e4d5d5Solivier moysan * Preamble, CS, user, validity and parity error bits not copied 35103e4d5d5Solivier moysan * to DR register. 35203e4d5d5Solivier moysan */ 35303e4d5d5Solivier moysan cr = SPDIFRX_CR_WFA | SPDIFRX_CR_PMSK | SPDIFRX_CR_VMSK | 35403e4d5d5Solivier moysan SPDIFRX_CR_CUMSK | SPDIFRX_CR_PTMSK | SPDIFRX_CR_RXSTEO; 35503e4d5d5Solivier moysan cr_mask = cr; 35603e4d5d5Solivier moysan 3570c93c291SOlivier Moysan cr |= SPDIFRX_CR_NBTRSET(SPDIFRX_NBTR_63); 3580c93c291SOlivier Moysan cr_mask |= SPDIFRX_CR_NBTR_MASK; 35903e4d5d5Solivier moysan cr |= SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); 36003e4d5d5Solivier moysan cr_mask |= SPDIFRX_CR_SPDIFEN_MASK; 36103e4d5d5Solivier moysan ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 36203e4d5d5Solivier moysan cr_mask, cr); 36303e4d5d5Solivier moysan if (ret < 0) 36403e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, 36503e4d5d5Solivier moysan "Failed to start synchronization\n"); 36603e4d5d5Solivier moysan } 36703e4d5d5Solivier moysan 3682859b178SOlivier Moysan spin_unlock_irqrestore(&spdifrx->lock, flags); 36903e4d5d5Solivier moysan 37003e4d5d5Solivier moysan return ret; 37103e4d5d5Solivier moysan } 37203e4d5d5Solivier moysan 37303e4d5d5Solivier moysan static void stm32_spdifrx_stop(struct stm32_spdifrx_data *spdifrx) 37403e4d5d5Solivier moysan { 37503e4d5d5Solivier moysan int cr, cr_mask, reg; 3762859b178SOlivier Moysan unsigned long flags; 37703e4d5d5Solivier moysan 3782859b178SOlivier Moysan spin_lock_irqsave(&spdifrx->lock, flags); 37903e4d5d5Solivier moysan 38003e4d5d5Solivier moysan if (--spdifrx->refcount) { 3812859b178SOlivier Moysan spin_unlock_irqrestore(&spdifrx->lock, flags); 38203e4d5d5Solivier moysan return; 38303e4d5d5Solivier moysan } 38403e4d5d5Solivier moysan 38503e4d5d5Solivier moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); 38603e4d5d5Solivier moysan cr_mask = SPDIFRX_CR_SPDIFEN_MASK | SPDIFRX_CR_RXDMAEN; 38703e4d5d5Solivier moysan 38803e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, cr_mask, cr); 38903e4d5d5Solivier moysan 39003e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, 39103e4d5d5Solivier moysan SPDIFRX_XIMR_MASK, 0); 39203e4d5d5Solivier moysan 39303e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, 39403e4d5d5Solivier moysan SPDIFRX_XIFCR_MASK, SPDIFRX_XIFCR_MASK); 39503e4d5d5Solivier moysan 39603e4d5d5Solivier moysan /* dummy read to clear CSRNE and RXNE in status register */ 39703e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_DR, ®); 39803e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_CSR, ®); 39903e4d5d5Solivier moysan 4002859b178SOlivier Moysan spin_unlock_irqrestore(&spdifrx->lock, flags); 40103e4d5d5Solivier moysan } 40203e4d5d5Solivier moysan 40303e4d5d5Solivier moysan static int stm32_spdifrx_dma_ctrl_register(struct device *dev, 40403e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx) 40503e4d5d5Solivier moysan { 40603e4d5d5Solivier moysan int ret; 40703e4d5d5Solivier moysan 40898c8dc2fSolivier moysan spdifrx->ctrl_chan = dma_request_chan(dev, "rx-ctrl"); 40998c8dc2fSolivier moysan if (IS_ERR(spdifrx->ctrl_chan)) { 41098c8dc2fSolivier moysan dev_err(dev, "dma_request_slave_channel failed\n"); 41198c8dc2fSolivier moysan return PTR_ERR(spdifrx->ctrl_chan); 41298c8dc2fSolivier moysan } 41398c8dc2fSolivier moysan 41403e4d5d5Solivier moysan spdifrx->dmab = devm_kzalloc(dev, sizeof(struct snd_dma_buffer), 41503e4d5d5Solivier moysan GFP_KERNEL); 41603e4d5d5Solivier moysan if (!spdifrx->dmab) 41703e4d5d5Solivier moysan return -ENOMEM; 41803e4d5d5Solivier moysan 41903e4d5d5Solivier moysan spdifrx->dmab->dev.type = SNDRV_DMA_TYPE_DEV_IRAM; 42003e4d5d5Solivier moysan spdifrx->dmab->dev.dev = dev; 42103e4d5d5Solivier moysan ret = snd_dma_alloc_pages(spdifrx->dmab->dev.type, dev, 42203e4d5d5Solivier moysan SPDIFRX_CSR_BUF_LENGTH, spdifrx->dmab); 42303e4d5d5Solivier moysan if (ret < 0) { 42403e4d5d5Solivier moysan dev_err(dev, "snd_dma_alloc_pages returned error %d\n", ret); 42503e4d5d5Solivier moysan return ret; 42603e4d5d5Solivier moysan } 42703e4d5d5Solivier moysan 42803e4d5d5Solivier moysan spdifrx->slave_config.direction = DMA_DEV_TO_MEM; 42903e4d5d5Solivier moysan spdifrx->slave_config.src_addr = (dma_addr_t)(spdifrx->phys_addr + 43003e4d5d5Solivier moysan STM32_SPDIFRX_CSR); 43103e4d5d5Solivier moysan spdifrx->slave_config.dst_addr = spdifrx->dmab->addr; 43203e4d5d5Solivier moysan spdifrx->slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 43303e4d5d5Solivier moysan spdifrx->slave_config.src_maxburst = 1; 43403e4d5d5Solivier moysan 43503e4d5d5Solivier moysan ret = dmaengine_slave_config(spdifrx->ctrl_chan, 43603e4d5d5Solivier moysan &spdifrx->slave_config); 43703e4d5d5Solivier moysan if (ret < 0) { 43803e4d5d5Solivier moysan dev_err(dev, "dmaengine_slave_config returned error %d\n", ret); 43903e4d5d5Solivier moysan spdifrx->ctrl_chan = NULL; 44003e4d5d5Solivier moysan } 44103e4d5d5Solivier moysan 44203e4d5d5Solivier moysan return ret; 44303e4d5d5Solivier moysan }; 44403e4d5d5Solivier moysan 44503e4d5d5Solivier moysan static const char * const spdifrx_enum_input[] = { 44603e4d5d5Solivier moysan "in0", "in1", "in2", "in3" 44703e4d5d5Solivier moysan }; 44803e4d5d5Solivier moysan 44903e4d5d5Solivier moysan /* By default CS bits are retrieved from channel A */ 45003e4d5d5Solivier moysan static const char * const spdifrx_enum_cs_channel[] = { 45103e4d5d5Solivier moysan "A", "B" 45203e4d5d5Solivier moysan }; 45303e4d5d5Solivier moysan 45403e4d5d5Solivier moysan static SOC_ENUM_SINGLE_DECL(ctrl_enum_input, 45503e4d5d5Solivier moysan STM32_SPDIFRX_CR, SPDIFRX_CR_INSEL_SHIFT, 45603e4d5d5Solivier moysan spdifrx_enum_input); 45703e4d5d5Solivier moysan 45803e4d5d5Solivier moysan static SOC_ENUM_SINGLE_DECL(ctrl_enum_cs_channel, 45903e4d5d5Solivier moysan STM32_SPDIFRX_CR, SPDIFRX_CR_CHSEL_SHIFT, 46003e4d5d5Solivier moysan spdifrx_enum_cs_channel); 46103e4d5d5Solivier moysan 46203e4d5d5Solivier moysan static int stm32_spdifrx_info(struct snd_kcontrol *kcontrol, 46303e4d5d5Solivier moysan struct snd_ctl_elem_info *uinfo) 46403e4d5d5Solivier moysan { 46503e4d5d5Solivier moysan uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 46603e4d5d5Solivier moysan uinfo->count = 1; 46703e4d5d5Solivier moysan 46803e4d5d5Solivier moysan return 0; 46903e4d5d5Solivier moysan } 47003e4d5d5Solivier moysan 47103e4d5d5Solivier moysan static int stm32_spdifrx_ub_info(struct snd_kcontrol *kcontrol, 47203e4d5d5Solivier moysan struct snd_ctl_elem_info *uinfo) 47303e4d5d5Solivier moysan { 47403e4d5d5Solivier moysan uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 47503e4d5d5Solivier moysan uinfo->count = 1; 47603e4d5d5Solivier moysan 47703e4d5d5Solivier moysan return 0; 47803e4d5d5Solivier moysan } 47903e4d5d5Solivier moysan 48003e4d5d5Solivier moysan static int stm32_spdifrx_get_ctrl_data(struct stm32_spdifrx_data *spdifrx) 48103e4d5d5Solivier moysan { 48203e4d5d5Solivier moysan int ret = 0; 48303e4d5d5Solivier moysan 48403e4d5d5Solivier moysan memset(spdifrx->cs, 0, SPDIFRX_CS_BYTES_NB); 48503e4d5d5Solivier moysan memset(spdifrx->ub, 0, SPDIFRX_UB_BYTES_NB); 48603e4d5d5Solivier moysan 487f68c2a68SOlivier Moysan pinctrl_pm_select_default_state(&spdifrx->pdev->dev); 488f68c2a68SOlivier Moysan 48903e4d5d5Solivier moysan ret = stm32_spdifrx_dma_ctrl_start(spdifrx); 49003e4d5d5Solivier moysan if (ret < 0) 49103e4d5d5Solivier moysan return ret; 49203e4d5d5Solivier moysan 49303e4d5d5Solivier moysan ret = clk_prepare_enable(spdifrx->kclk); 49403e4d5d5Solivier moysan if (ret) { 49503e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); 49603e4d5d5Solivier moysan return ret; 49703e4d5d5Solivier moysan } 49803e4d5d5Solivier moysan 49903e4d5d5Solivier moysan ret = regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 50003e4d5d5Solivier moysan SPDIFRX_CR_CBDMAEN, SPDIFRX_CR_CBDMAEN); 50103e4d5d5Solivier moysan if (ret < 0) 50203e4d5d5Solivier moysan goto end; 50303e4d5d5Solivier moysan 50403e4d5d5Solivier moysan ret = stm32_spdifrx_start_sync(spdifrx); 50503e4d5d5Solivier moysan if (ret < 0) 50603e4d5d5Solivier moysan goto end; 50703e4d5d5Solivier moysan 50803e4d5d5Solivier moysan if (wait_for_completion_interruptible_timeout(&spdifrx->cs_completion, 50903e4d5d5Solivier moysan msecs_to_jiffies(100)) 51003e4d5d5Solivier moysan <= 0) { 51119e42536SOlivier Moysan dev_dbg(&spdifrx->pdev->dev, "Failed to get control data\n"); 51203e4d5d5Solivier moysan ret = -EAGAIN; 51303e4d5d5Solivier moysan } 51403e4d5d5Solivier moysan 51503e4d5d5Solivier moysan stm32_spdifrx_stop(spdifrx); 51603e4d5d5Solivier moysan stm32_spdifrx_dma_ctrl_stop(spdifrx); 51703e4d5d5Solivier moysan 51803e4d5d5Solivier moysan end: 51903e4d5d5Solivier moysan clk_disable_unprepare(spdifrx->kclk); 520f68c2a68SOlivier Moysan pinctrl_pm_select_sleep_state(&spdifrx->pdev->dev); 52103e4d5d5Solivier moysan 52203e4d5d5Solivier moysan return ret; 52303e4d5d5Solivier moysan } 52403e4d5d5Solivier moysan 52503e4d5d5Solivier moysan static int stm32_spdifrx_capture_get(struct snd_kcontrol *kcontrol, 52603e4d5d5Solivier moysan struct snd_ctl_elem_value *ucontrol) 52703e4d5d5Solivier moysan { 52803e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 52903e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 53003e4d5d5Solivier moysan 53103e4d5d5Solivier moysan stm32_spdifrx_get_ctrl_data(spdifrx); 53203e4d5d5Solivier moysan 53303e4d5d5Solivier moysan ucontrol->value.iec958.status[0] = spdifrx->cs[0]; 53403e4d5d5Solivier moysan ucontrol->value.iec958.status[1] = spdifrx->cs[1]; 53503e4d5d5Solivier moysan ucontrol->value.iec958.status[2] = spdifrx->cs[2]; 53603e4d5d5Solivier moysan ucontrol->value.iec958.status[3] = spdifrx->cs[3]; 53703e4d5d5Solivier moysan ucontrol->value.iec958.status[4] = spdifrx->cs[4]; 53803e4d5d5Solivier moysan 53903e4d5d5Solivier moysan return 0; 54003e4d5d5Solivier moysan } 54103e4d5d5Solivier moysan 54203e4d5d5Solivier moysan static int stm32_spdif_user_bits_get(struct snd_kcontrol *kcontrol, 54303e4d5d5Solivier moysan struct snd_ctl_elem_value *ucontrol) 54403e4d5d5Solivier moysan { 54503e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai = snd_kcontrol_chip(kcontrol); 54603e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 54703e4d5d5Solivier moysan 54803e4d5d5Solivier moysan stm32_spdifrx_get_ctrl_data(spdifrx); 54903e4d5d5Solivier moysan 55003e4d5d5Solivier moysan ucontrol->value.iec958.status[0] = spdifrx->ub[0]; 55103e4d5d5Solivier moysan ucontrol->value.iec958.status[1] = spdifrx->ub[1]; 55203e4d5d5Solivier moysan ucontrol->value.iec958.status[2] = spdifrx->ub[2]; 55303e4d5d5Solivier moysan ucontrol->value.iec958.status[3] = spdifrx->ub[3]; 55403e4d5d5Solivier moysan ucontrol->value.iec958.status[4] = spdifrx->ub[4]; 55503e4d5d5Solivier moysan 55603e4d5d5Solivier moysan return 0; 55703e4d5d5Solivier moysan } 55803e4d5d5Solivier moysan 55903e4d5d5Solivier moysan static struct snd_kcontrol_new stm32_spdifrx_iec_ctrls[] = { 56003e4d5d5Solivier moysan /* Channel status control */ 56103e4d5d5Solivier moysan { 56203e4d5d5Solivier moysan .iface = SNDRV_CTL_ELEM_IFACE_PCM, 56303e4d5d5Solivier moysan .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), 56403e4d5d5Solivier moysan .access = SNDRV_CTL_ELEM_ACCESS_READ | 56503e4d5d5Solivier moysan SNDRV_CTL_ELEM_ACCESS_VOLATILE, 56603e4d5d5Solivier moysan .info = stm32_spdifrx_info, 56703e4d5d5Solivier moysan .get = stm32_spdifrx_capture_get, 56803e4d5d5Solivier moysan }, 56903e4d5d5Solivier moysan /* User bits control */ 57003e4d5d5Solivier moysan { 57103e4d5d5Solivier moysan .iface = SNDRV_CTL_ELEM_IFACE_PCM, 57203e4d5d5Solivier moysan .name = "IEC958 User Bit Capture Default", 57303e4d5d5Solivier moysan .access = SNDRV_CTL_ELEM_ACCESS_READ | 57403e4d5d5Solivier moysan SNDRV_CTL_ELEM_ACCESS_VOLATILE, 57503e4d5d5Solivier moysan .info = stm32_spdifrx_ub_info, 57603e4d5d5Solivier moysan .get = stm32_spdif_user_bits_get, 57703e4d5d5Solivier moysan }, 57803e4d5d5Solivier moysan }; 57903e4d5d5Solivier moysan 58003e4d5d5Solivier moysan static struct snd_kcontrol_new stm32_spdifrx_ctrls[] = { 58103e4d5d5Solivier moysan SOC_ENUM("SPDIFRX input", ctrl_enum_input), 58203e4d5d5Solivier moysan SOC_ENUM("SPDIFRX CS channel", ctrl_enum_cs_channel), 58303e4d5d5Solivier moysan }; 58403e4d5d5Solivier moysan 58503e4d5d5Solivier moysan static int stm32_spdifrx_dai_register_ctrls(struct snd_soc_dai *cpu_dai) 58603e4d5d5Solivier moysan { 58703e4d5d5Solivier moysan int ret; 58803e4d5d5Solivier moysan 58903e4d5d5Solivier moysan ret = snd_soc_add_dai_controls(cpu_dai, stm32_spdifrx_iec_ctrls, 59003e4d5d5Solivier moysan ARRAY_SIZE(stm32_spdifrx_iec_ctrls)); 59103e4d5d5Solivier moysan if (ret < 0) 59203e4d5d5Solivier moysan return ret; 59303e4d5d5Solivier moysan 59403e4d5d5Solivier moysan return snd_soc_add_component_controls(cpu_dai->component, 59503e4d5d5Solivier moysan stm32_spdifrx_ctrls, 59603e4d5d5Solivier moysan ARRAY_SIZE(stm32_spdifrx_ctrls)); 59703e4d5d5Solivier moysan } 59803e4d5d5Solivier moysan 59903e4d5d5Solivier moysan static int stm32_spdifrx_dai_probe(struct snd_soc_dai *cpu_dai) 60003e4d5d5Solivier moysan { 60103e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(cpu_dai->dev); 60203e4d5d5Solivier moysan 60303e4d5d5Solivier moysan spdifrx->dma_params.addr = (dma_addr_t)(spdifrx->phys_addr + 60403e4d5d5Solivier moysan STM32_SPDIFRX_DR); 60503e4d5d5Solivier moysan spdifrx->dma_params.maxburst = 1; 60603e4d5d5Solivier moysan 60703e4d5d5Solivier moysan snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); 60803e4d5d5Solivier moysan 60903e4d5d5Solivier moysan return stm32_spdifrx_dai_register_ctrls(cpu_dai); 61003e4d5d5Solivier moysan } 61103e4d5d5Solivier moysan 61203e4d5d5Solivier moysan static bool stm32_spdifrx_readable_reg(struct device *dev, unsigned int reg) 61303e4d5d5Solivier moysan { 61403e4d5d5Solivier moysan switch (reg) { 61503e4d5d5Solivier moysan case STM32_SPDIFRX_CR: 61603e4d5d5Solivier moysan case STM32_SPDIFRX_IMR: 61703e4d5d5Solivier moysan case STM32_SPDIFRX_SR: 61803e4d5d5Solivier moysan case STM32_SPDIFRX_IFCR: 61903e4d5d5Solivier moysan case STM32_SPDIFRX_DR: 62003e4d5d5Solivier moysan case STM32_SPDIFRX_CSR: 62103e4d5d5Solivier moysan case STM32_SPDIFRX_DIR: 6221a5c0b28SOlivier Moysan case STM32_SPDIFRX_VERR: 6231a5c0b28SOlivier Moysan case STM32_SPDIFRX_IDR: 6241a5c0b28SOlivier Moysan case STM32_SPDIFRX_SIDR: 62503e4d5d5Solivier moysan return true; 62603e4d5d5Solivier moysan default: 62703e4d5d5Solivier moysan return false; 62803e4d5d5Solivier moysan } 62903e4d5d5Solivier moysan } 63003e4d5d5Solivier moysan 63103e4d5d5Solivier moysan static bool stm32_spdifrx_volatile_reg(struct device *dev, unsigned int reg) 63203e4d5d5Solivier moysan { 633f68c2a68SOlivier Moysan switch (reg) { 634f68c2a68SOlivier Moysan case STM32_SPDIFRX_DR: 635f68c2a68SOlivier Moysan case STM32_SPDIFRX_CSR: 636f68c2a68SOlivier Moysan case STM32_SPDIFRX_SR: 637f68c2a68SOlivier Moysan case STM32_SPDIFRX_DIR: 63803e4d5d5Solivier moysan return true; 639f68c2a68SOlivier Moysan default: 64003e4d5d5Solivier moysan return false; 64103e4d5d5Solivier moysan } 642f68c2a68SOlivier Moysan } 64303e4d5d5Solivier moysan 64403e4d5d5Solivier moysan static bool stm32_spdifrx_writeable_reg(struct device *dev, unsigned int reg) 64503e4d5d5Solivier moysan { 64603e4d5d5Solivier moysan switch (reg) { 64703e4d5d5Solivier moysan case STM32_SPDIFRX_CR: 64803e4d5d5Solivier moysan case STM32_SPDIFRX_IMR: 64903e4d5d5Solivier moysan case STM32_SPDIFRX_IFCR: 65003e4d5d5Solivier moysan return true; 65103e4d5d5Solivier moysan default: 65203e4d5d5Solivier moysan return false; 65303e4d5d5Solivier moysan } 65403e4d5d5Solivier moysan } 65503e4d5d5Solivier moysan 65603e4d5d5Solivier moysan static const struct regmap_config stm32_h7_spdifrx_regmap_conf = { 65703e4d5d5Solivier moysan .reg_bits = 32, 65803e4d5d5Solivier moysan .reg_stride = 4, 65903e4d5d5Solivier moysan .val_bits = 32, 6601a5c0b28SOlivier Moysan .max_register = STM32_SPDIFRX_SIDR, 66103e4d5d5Solivier moysan .readable_reg = stm32_spdifrx_readable_reg, 66203e4d5d5Solivier moysan .volatile_reg = stm32_spdifrx_volatile_reg, 66303e4d5d5Solivier moysan .writeable_reg = stm32_spdifrx_writeable_reg, 6641a5c0b28SOlivier Moysan .num_reg_defaults_raw = STM32_SPDIFRX_SIDR / sizeof(u32) + 1, 66503e4d5d5Solivier moysan .fast_io = true, 666f68c2a68SOlivier Moysan .cache_type = REGCACHE_FLAT, 66703e4d5d5Solivier moysan }; 66803e4d5d5Solivier moysan 66903e4d5d5Solivier moysan static irqreturn_t stm32_spdifrx_isr(int irq, void *devid) 67003e4d5d5Solivier moysan { 67103e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = (struct stm32_spdifrx_data *)devid; 67203e4d5d5Solivier moysan struct platform_device *pdev = spdifrx->pdev; 67303e4d5d5Solivier moysan unsigned int cr, mask, sr, imr; 6740c93c291SOlivier Moysan unsigned int flags, sync_state; 67503e4d5d5Solivier moysan int err = 0, err_xrun = 0; 67603e4d5d5Solivier moysan 67703e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_SR, &sr); 67803e4d5d5Solivier moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_IMR, &imr); 67903e4d5d5Solivier moysan 68003e4d5d5Solivier moysan mask = imr & SPDIFRX_XIMR_MASK; 68103e4d5d5Solivier moysan /* SERR, TERR, FERR IRQs are generated if IFEIE is set */ 68203e4d5d5Solivier moysan if (mask & SPDIFRX_IMR_IFEIE) 68303e4d5d5Solivier moysan mask |= (SPDIFRX_IMR_IFEIE << 1) | (SPDIFRX_IMR_IFEIE << 2); 68403e4d5d5Solivier moysan 68503e4d5d5Solivier moysan flags = sr & mask; 68603e4d5d5Solivier moysan if (!flags) { 68703e4d5d5Solivier moysan dev_err(&pdev->dev, "Unexpected IRQ. rflags=%#x, imr=%#x\n", 68803e4d5d5Solivier moysan sr, imr); 68903e4d5d5Solivier moysan return IRQ_NONE; 69003e4d5d5Solivier moysan } 69103e4d5d5Solivier moysan 69203e4d5d5Solivier moysan /* Clear IRQs */ 69303e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IFCR, 69403e4d5d5Solivier moysan SPDIFRX_XIFCR_MASK, flags); 69503e4d5d5Solivier moysan 69603e4d5d5Solivier moysan if (flags & SPDIFRX_SR_PERR) { 69703e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Parity error\n"); 69803e4d5d5Solivier moysan err_xrun = 1; 69903e4d5d5Solivier moysan } 70003e4d5d5Solivier moysan 70103e4d5d5Solivier moysan if (flags & SPDIFRX_SR_OVR) { 70203e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Overrun error\n"); 70303e4d5d5Solivier moysan err_xrun = 1; 70403e4d5d5Solivier moysan } 70503e4d5d5Solivier moysan 70603e4d5d5Solivier moysan if (flags & SPDIFRX_SR_SBD) 70703e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Synchronization block detected\n"); 70803e4d5d5Solivier moysan 70903e4d5d5Solivier moysan if (flags & SPDIFRX_SR_SYNCD) { 71003e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Synchronization done\n"); 71103e4d5d5Solivier moysan 71203e4d5d5Solivier moysan /* Enable spdifrx */ 71303e4d5d5Solivier moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_ENABLE); 71403e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 71503e4d5d5Solivier moysan SPDIFRX_CR_SPDIFEN_MASK, cr); 71603e4d5d5Solivier moysan } 71703e4d5d5Solivier moysan 71803e4d5d5Solivier moysan if (flags & SPDIFRX_SR_FERR) { 71903e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Frame error\n"); 72003e4d5d5Solivier moysan err = 1; 72103e4d5d5Solivier moysan } 72203e4d5d5Solivier moysan 72303e4d5d5Solivier moysan if (flags & SPDIFRX_SR_SERR) { 72403e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Synchronization error\n"); 72503e4d5d5Solivier moysan err = 1; 72603e4d5d5Solivier moysan } 72703e4d5d5Solivier moysan 72803e4d5d5Solivier moysan if (flags & SPDIFRX_SR_TERR) { 72903e4d5d5Solivier moysan dev_dbg(&pdev->dev, "Timeout error\n"); 73003e4d5d5Solivier moysan err = 1; 73103e4d5d5Solivier moysan } 73203e4d5d5Solivier moysan 73303e4d5d5Solivier moysan if (err) { 7340c93c291SOlivier Moysan regmap_read(spdifrx->regmap, STM32_SPDIFRX_CR, &cr); 7350c93c291SOlivier Moysan sync_state = FIELD_GET(SPDIFRX_CR_SPDIFEN_MASK, cr) && 7360c93c291SOlivier Moysan SPDIFRX_SPDIFEN_SYNC; 7370c93c291SOlivier Moysan 7380c93c291SOlivier Moysan /* SPDIFRX is in STATE_STOP. Disable SPDIFRX to clear errors */ 73903e4d5d5Solivier moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_DISABLE); 74003e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 74103e4d5d5Solivier moysan SPDIFRX_CR_SPDIFEN_MASK, cr); 74203e4d5d5Solivier moysan 7430c93c291SOlivier Moysan /* If SPDIFRX was in STATE_SYNC, retry synchro */ 7440c93c291SOlivier Moysan if (sync_state) { 7450c93c291SOlivier Moysan cr = SPDIFRX_CR_SPDIFENSET(SPDIFRX_SPDIFEN_SYNC); 7460c93c291SOlivier Moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 7470c93c291SOlivier Moysan SPDIFRX_CR_SPDIFEN_MASK, cr); 7480c93c291SOlivier Moysan return IRQ_HANDLED; 7490c93c291SOlivier Moysan } 7500c93c291SOlivier Moysan 751*86e1956aSOlivier Moysan spin_lock(&spdifrx->irq_lock); 752*86e1956aSOlivier Moysan if (spdifrx->substream) 753*86e1956aSOlivier Moysan snd_pcm_stop(spdifrx->substream, 754*86e1956aSOlivier Moysan SNDRV_PCM_STATE_DISCONNECTED); 755*86e1956aSOlivier Moysan spin_unlock(&spdifrx->irq_lock); 75603e4d5d5Solivier moysan 75703e4d5d5Solivier moysan return IRQ_HANDLED; 75803e4d5d5Solivier moysan } 75903e4d5d5Solivier moysan 760*86e1956aSOlivier Moysan spin_lock(&spdifrx->irq_lock); 761*86e1956aSOlivier Moysan if (err_xrun && spdifrx->substream) 762*86e1956aSOlivier Moysan snd_pcm_stop_xrun(spdifrx->substream); 763*86e1956aSOlivier Moysan spin_unlock(&spdifrx->irq_lock); 76403e4d5d5Solivier moysan 76503e4d5d5Solivier moysan return IRQ_HANDLED; 76603e4d5d5Solivier moysan } 76703e4d5d5Solivier moysan 76803e4d5d5Solivier moysan static int stm32_spdifrx_startup(struct snd_pcm_substream *substream, 76903e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 77003e4d5d5Solivier moysan { 77103e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 772*86e1956aSOlivier Moysan unsigned long flags; 77303e4d5d5Solivier moysan int ret; 77403e4d5d5Solivier moysan 775*86e1956aSOlivier Moysan spin_lock_irqsave(&spdifrx->irq_lock, flags); 77603e4d5d5Solivier moysan spdifrx->substream = substream; 777*86e1956aSOlivier Moysan spin_unlock_irqrestore(&spdifrx->irq_lock, flags); 77803e4d5d5Solivier moysan 77903e4d5d5Solivier moysan ret = clk_prepare_enable(spdifrx->kclk); 78003e4d5d5Solivier moysan if (ret) 78103e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Enable kclk failed: %d\n", ret); 78203e4d5d5Solivier moysan 78303e4d5d5Solivier moysan return ret; 78403e4d5d5Solivier moysan } 78503e4d5d5Solivier moysan 78603e4d5d5Solivier moysan static int stm32_spdifrx_hw_params(struct snd_pcm_substream *substream, 78703e4d5d5Solivier moysan struct snd_pcm_hw_params *params, 78803e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 78903e4d5d5Solivier moysan { 79003e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 79103e4d5d5Solivier moysan int data_size = params_width(params); 79203e4d5d5Solivier moysan int fmt; 79303e4d5d5Solivier moysan 79403e4d5d5Solivier moysan switch (data_size) { 79503e4d5d5Solivier moysan case 16: 79603e4d5d5Solivier moysan fmt = SPDIFRX_DRFMT_PACKED; 79703e4d5d5Solivier moysan break; 79803e4d5d5Solivier moysan case 32: 79903e4d5d5Solivier moysan fmt = SPDIFRX_DRFMT_LEFT; 80003e4d5d5Solivier moysan break; 80103e4d5d5Solivier moysan default: 80203e4d5d5Solivier moysan dev_err(&spdifrx->pdev->dev, "Unexpected data format\n"); 80303e4d5d5Solivier moysan return -EINVAL; 80403e4d5d5Solivier moysan } 80503e4d5d5Solivier moysan 8069036e4acSolivier moysan /* 8079036e4acSolivier moysan * Set buswidth to 4 bytes for all data formats. 8089036e4acSolivier moysan * Packed format: transfer 2 x 2 bytes samples 8099036e4acSolivier moysan * Left format: transfer 1 x 3 bytes samples + 1 dummy byte 8109036e4acSolivier moysan */ 8119036e4acSolivier moysan spdifrx->dma_params.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 81203e4d5d5Solivier moysan snd_soc_dai_init_dma_data(cpu_dai, NULL, &spdifrx->dma_params); 81303e4d5d5Solivier moysan 81403e4d5d5Solivier moysan return regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 81503e4d5d5Solivier moysan SPDIFRX_CR_DRFMT_MASK, 81603e4d5d5Solivier moysan SPDIFRX_CR_DRFMTSET(fmt)); 81703e4d5d5Solivier moysan } 81803e4d5d5Solivier moysan 81903e4d5d5Solivier moysan static int stm32_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd, 82003e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 82103e4d5d5Solivier moysan { 82203e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 82303e4d5d5Solivier moysan int ret = 0; 82403e4d5d5Solivier moysan 82503e4d5d5Solivier moysan switch (cmd) { 82603e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_START: 82703e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_RESUME: 82803e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 82903e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_IMR, 83003e4d5d5Solivier moysan SPDIFRX_IMR_OVRIE, SPDIFRX_IMR_OVRIE); 83103e4d5d5Solivier moysan 83203e4d5d5Solivier moysan regmap_update_bits(spdifrx->regmap, STM32_SPDIFRX_CR, 83303e4d5d5Solivier moysan SPDIFRX_CR_RXDMAEN, SPDIFRX_CR_RXDMAEN); 83403e4d5d5Solivier moysan 83503e4d5d5Solivier moysan ret = stm32_spdifrx_start_sync(spdifrx); 83603e4d5d5Solivier moysan break; 83703e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_SUSPEND: 83803e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 83903e4d5d5Solivier moysan case SNDRV_PCM_TRIGGER_STOP: 84003e4d5d5Solivier moysan stm32_spdifrx_stop(spdifrx); 84103e4d5d5Solivier moysan break; 84203e4d5d5Solivier moysan default: 84303e4d5d5Solivier moysan return -EINVAL; 84403e4d5d5Solivier moysan } 84503e4d5d5Solivier moysan 84603e4d5d5Solivier moysan return ret; 84703e4d5d5Solivier moysan } 84803e4d5d5Solivier moysan 84903e4d5d5Solivier moysan static void stm32_spdifrx_shutdown(struct snd_pcm_substream *substream, 85003e4d5d5Solivier moysan struct snd_soc_dai *cpu_dai) 85103e4d5d5Solivier moysan { 85203e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = snd_soc_dai_get_drvdata(cpu_dai); 853*86e1956aSOlivier Moysan unsigned long flags; 85403e4d5d5Solivier moysan 855*86e1956aSOlivier Moysan spin_lock_irqsave(&spdifrx->irq_lock, flags); 85603e4d5d5Solivier moysan spdifrx->substream = NULL; 857*86e1956aSOlivier Moysan spin_unlock_irqrestore(&spdifrx->irq_lock, flags); 858*86e1956aSOlivier Moysan 85903e4d5d5Solivier moysan clk_disable_unprepare(spdifrx->kclk); 86003e4d5d5Solivier moysan } 86103e4d5d5Solivier moysan 86203e4d5d5Solivier moysan static const struct snd_soc_dai_ops stm32_spdifrx_pcm_dai_ops = { 86303e4d5d5Solivier moysan .startup = stm32_spdifrx_startup, 86403e4d5d5Solivier moysan .hw_params = stm32_spdifrx_hw_params, 86503e4d5d5Solivier moysan .trigger = stm32_spdifrx_trigger, 86603e4d5d5Solivier moysan .shutdown = stm32_spdifrx_shutdown, 86703e4d5d5Solivier moysan }; 86803e4d5d5Solivier moysan 86903e4d5d5Solivier moysan static struct snd_soc_dai_driver stm32_spdifrx_dai[] = { 87003e4d5d5Solivier moysan { 87103e4d5d5Solivier moysan .probe = stm32_spdifrx_dai_probe, 87203e4d5d5Solivier moysan .capture = { 87303e4d5d5Solivier moysan .stream_name = "CPU-Capture", 87403e4d5d5Solivier moysan .channels_min = 1, 87503e4d5d5Solivier moysan .channels_max = 2, 87603e4d5d5Solivier moysan .rates = SNDRV_PCM_RATE_8000_192000, 87703e4d5d5Solivier moysan .formats = SNDRV_PCM_FMTBIT_S32_LE | 87803e4d5d5Solivier moysan SNDRV_PCM_FMTBIT_S16_LE, 87903e4d5d5Solivier moysan }, 88003e4d5d5Solivier moysan .ops = &stm32_spdifrx_pcm_dai_ops, 88103e4d5d5Solivier moysan } 88203e4d5d5Solivier moysan }; 88303e4d5d5Solivier moysan 88403e4d5d5Solivier moysan static const struct snd_pcm_hardware stm32_spdifrx_pcm_hw = { 88503e4d5d5Solivier moysan .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP, 88603e4d5d5Solivier moysan .buffer_bytes_max = 8 * PAGE_SIZE, 887863137f0SOlivier Moysan .period_bytes_min = 1024, 888863137f0SOlivier Moysan .period_bytes_max = 4 * PAGE_SIZE, 88903e4d5d5Solivier moysan .periods_min = 2, 89003e4d5d5Solivier moysan .periods_max = 8, 89103e4d5d5Solivier moysan }; 89203e4d5d5Solivier moysan 89303e4d5d5Solivier moysan static const struct snd_soc_component_driver stm32_spdifrx_component = { 89403e4d5d5Solivier moysan .name = "stm32-spdifrx", 89503e4d5d5Solivier moysan }; 89603e4d5d5Solivier moysan 89703e4d5d5Solivier moysan static const struct snd_dmaengine_pcm_config stm32_spdifrx_pcm_config = { 89803e4d5d5Solivier moysan .pcm_hardware = &stm32_spdifrx_pcm_hw, 89903e4d5d5Solivier moysan .prepare_slave_config = snd_dmaengine_pcm_prepare_slave_config, 90003e4d5d5Solivier moysan }; 90103e4d5d5Solivier moysan 90203e4d5d5Solivier moysan static const struct of_device_id stm32_spdifrx_ids[] = { 90303e4d5d5Solivier moysan { 90403e4d5d5Solivier moysan .compatible = "st,stm32h7-spdifrx", 90503e4d5d5Solivier moysan .data = &stm32_h7_spdifrx_regmap_conf 90603e4d5d5Solivier moysan }, 90703e4d5d5Solivier moysan {} 90803e4d5d5Solivier moysan }; 90903e4d5d5Solivier moysan 910b9aa4716Solivier moysan static int stm32_spdifrx_parse_of(struct platform_device *pdev, 91103e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx) 91203e4d5d5Solivier moysan { 91303e4d5d5Solivier moysan struct device_node *np = pdev->dev.of_node; 91403e4d5d5Solivier moysan const struct of_device_id *of_id; 91503e4d5d5Solivier moysan struct resource *res; 91603e4d5d5Solivier moysan 91703e4d5d5Solivier moysan if (!np) 91803e4d5d5Solivier moysan return -ENODEV; 91903e4d5d5Solivier moysan 92003e4d5d5Solivier moysan of_id = of_match_device(stm32_spdifrx_ids, &pdev->dev); 92103e4d5d5Solivier moysan if (of_id) 92203e4d5d5Solivier moysan spdifrx->regmap_conf = 92303e4d5d5Solivier moysan (const struct regmap_config *)of_id->data; 92403e4d5d5Solivier moysan else 92503e4d5d5Solivier moysan return -EINVAL; 92603e4d5d5Solivier moysan 92703e4d5d5Solivier moysan res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 92803e4d5d5Solivier moysan spdifrx->base = devm_ioremap_resource(&pdev->dev, res); 92903e4d5d5Solivier moysan if (IS_ERR(spdifrx->base)) 93003e4d5d5Solivier moysan return PTR_ERR(spdifrx->base); 93103e4d5d5Solivier moysan 93203e4d5d5Solivier moysan spdifrx->phys_addr = res->start; 93303e4d5d5Solivier moysan 93403e4d5d5Solivier moysan spdifrx->kclk = devm_clk_get(&pdev->dev, "kclk"); 93503e4d5d5Solivier moysan if (IS_ERR(spdifrx->kclk)) { 93603e4d5d5Solivier moysan dev_err(&pdev->dev, "Could not get kclk\n"); 93703e4d5d5Solivier moysan return PTR_ERR(spdifrx->kclk); 93803e4d5d5Solivier moysan } 93903e4d5d5Solivier moysan 94003e4d5d5Solivier moysan spdifrx->irq = platform_get_irq(pdev, 0); 941cf9441adSStephen Boyd if (spdifrx->irq < 0) 94203e4d5d5Solivier moysan return spdifrx->irq; 94303e4d5d5Solivier moysan 94403e4d5d5Solivier moysan return 0; 94503e4d5d5Solivier moysan } 94603e4d5d5Solivier moysan 94703e4d5d5Solivier moysan static int stm32_spdifrx_probe(struct platform_device *pdev) 94803e4d5d5Solivier moysan { 94903e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx; 95003e4d5d5Solivier moysan struct reset_control *rst; 95103e4d5d5Solivier moysan const struct snd_dmaengine_pcm_config *pcm_config = NULL; 9521a5c0b28SOlivier Moysan u32 ver, idr; 95303e4d5d5Solivier moysan int ret; 95403e4d5d5Solivier moysan 95503e4d5d5Solivier moysan spdifrx = devm_kzalloc(&pdev->dev, sizeof(*spdifrx), GFP_KERNEL); 95603e4d5d5Solivier moysan if (!spdifrx) 95703e4d5d5Solivier moysan return -ENOMEM; 95803e4d5d5Solivier moysan 95903e4d5d5Solivier moysan spdifrx->pdev = pdev; 96003e4d5d5Solivier moysan init_completion(&spdifrx->cs_completion); 96103e4d5d5Solivier moysan spin_lock_init(&spdifrx->lock); 962*86e1956aSOlivier Moysan spin_lock_init(&spdifrx->irq_lock); 96303e4d5d5Solivier moysan 96403e4d5d5Solivier moysan platform_set_drvdata(pdev, spdifrx); 96503e4d5d5Solivier moysan 966b9aa4716Solivier moysan ret = stm32_spdifrx_parse_of(pdev, spdifrx); 96703e4d5d5Solivier moysan if (ret) 96803e4d5d5Solivier moysan return ret; 96903e4d5d5Solivier moysan 97003e4d5d5Solivier moysan spdifrx->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "kclk", 97103e4d5d5Solivier moysan spdifrx->base, 97203e4d5d5Solivier moysan spdifrx->regmap_conf); 97303e4d5d5Solivier moysan if (IS_ERR(spdifrx->regmap)) { 97403e4d5d5Solivier moysan dev_err(&pdev->dev, "Regmap init failed\n"); 97503e4d5d5Solivier moysan return PTR_ERR(spdifrx->regmap); 97603e4d5d5Solivier moysan } 97703e4d5d5Solivier moysan 97803e4d5d5Solivier moysan ret = devm_request_irq(&pdev->dev, spdifrx->irq, stm32_spdifrx_isr, 0, 97903e4d5d5Solivier moysan dev_name(&pdev->dev), spdifrx); 98003e4d5d5Solivier moysan if (ret) { 98103e4d5d5Solivier moysan dev_err(&pdev->dev, "IRQ request returned %d\n", ret); 98203e4d5d5Solivier moysan return ret; 98303e4d5d5Solivier moysan } 98403e4d5d5Solivier moysan 985635eac1eSPhilipp Zabel rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); 98603e4d5d5Solivier moysan if (!IS_ERR(rst)) { 98703e4d5d5Solivier moysan reset_control_assert(rst); 98803e4d5d5Solivier moysan udelay(2); 98903e4d5d5Solivier moysan reset_control_deassert(rst); 99003e4d5d5Solivier moysan } 99103e4d5d5Solivier moysan 99203e4d5d5Solivier moysan ret = devm_snd_soc_register_component(&pdev->dev, 99303e4d5d5Solivier moysan &stm32_spdifrx_component, 99403e4d5d5Solivier moysan stm32_spdifrx_dai, 99503e4d5d5Solivier moysan ARRAY_SIZE(stm32_spdifrx_dai)); 99603e4d5d5Solivier moysan if (ret) 99703e4d5d5Solivier moysan return ret; 99803e4d5d5Solivier moysan 99903e4d5d5Solivier moysan ret = stm32_spdifrx_dma_ctrl_register(&pdev->dev, spdifrx); 100003e4d5d5Solivier moysan if (ret) 100103e4d5d5Solivier moysan goto error; 100203e4d5d5Solivier moysan 100303e4d5d5Solivier moysan pcm_config = &stm32_spdifrx_pcm_config; 100403e4d5d5Solivier moysan ret = devm_snd_dmaengine_pcm_register(&pdev->dev, pcm_config, 0); 100503e4d5d5Solivier moysan if (ret) { 100603e4d5d5Solivier moysan dev_err(&pdev->dev, "PCM DMA register returned %d\n", ret); 100703e4d5d5Solivier moysan goto error; 100803e4d5d5Solivier moysan } 100903e4d5d5Solivier moysan 10101a5c0b28SOlivier Moysan ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_IDR, &idr); 10111a5c0b28SOlivier Moysan if (ret) 10121a5c0b28SOlivier Moysan goto error; 10131a5c0b28SOlivier Moysan 10141a5c0b28SOlivier Moysan if (idr == SPDIFRX_IPIDR_NUMBER) { 10151a5c0b28SOlivier Moysan ret = regmap_read(spdifrx->regmap, STM32_SPDIFRX_VERR, &ver); 10161a5c0b28SOlivier Moysan 10171a5c0b28SOlivier Moysan dev_dbg(&pdev->dev, "SPDIFRX version: %lu.%lu registered\n", 10181a5c0b28SOlivier Moysan FIELD_GET(SPDIFRX_VERR_MAJ_MASK, ver), 10191a5c0b28SOlivier Moysan FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); 10201a5c0b28SOlivier Moysan } 10211a5c0b28SOlivier Moysan 10221a5c0b28SOlivier Moysan return ret; 102303e4d5d5Solivier moysan 102403e4d5d5Solivier moysan error: 102598c8dc2fSolivier moysan if (!IS_ERR(spdifrx->ctrl_chan)) 102603e4d5d5Solivier moysan dma_release_channel(spdifrx->ctrl_chan); 102703e4d5d5Solivier moysan if (spdifrx->dmab) 102803e4d5d5Solivier moysan snd_dma_free_pages(spdifrx->dmab); 102903e4d5d5Solivier moysan 103003e4d5d5Solivier moysan return ret; 103103e4d5d5Solivier moysan } 103203e4d5d5Solivier moysan 103303e4d5d5Solivier moysan static int stm32_spdifrx_remove(struct platform_device *pdev) 103403e4d5d5Solivier moysan { 103503e4d5d5Solivier moysan struct stm32_spdifrx_data *spdifrx = platform_get_drvdata(pdev); 103603e4d5d5Solivier moysan 103703e4d5d5Solivier moysan if (spdifrx->ctrl_chan) 103803e4d5d5Solivier moysan dma_release_channel(spdifrx->ctrl_chan); 103903e4d5d5Solivier moysan 104003e4d5d5Solivier moysan if (spdifrx->dmab) 104103e4d5d5Solivier moysan snd_dma_free_pages(spdifrx->dmab); 104203e4d5d5Solivier moysan 104303e4d5d5Solivier moysan return 0; 104403e4d5d5Solivier moysan } 104503e4d5d5Solivier moysan 104603e4d5d5Solivier moysan MODULE_DEVICE_TABLE(of, stm32_spdifrx_ids); 104703e4d5d5Solivier moysan 1048f68c2a68SOlivier Moysan #ifdef CONFIG_PM_SLEEP 1049f68c2a68SOlivier Moysan static int stm32_spdifrx_suspend(struct device *dev) 1050f68c2a68SOlivier Moysan { 1051f68c2a68SOlivier Moysan struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); 1052f68c2a68SOlivier Moysan 1053f68c2a68SOlivier Moysan regcache_cache_only(spdifrx->regmap, true); 1054f68c2a68SOlivier Moysan regcache_mark_dirty(spdifrx->regmap); 1055f68c2a68SOlivier Moysan 1056f68c2a68SOlivier Moysan return 0; 1057f68c2a68SOlivier Moysan } 1058f68c2a68SOlivier Moysan 1059f68c2a68SOlivier Moysan static int stm32_spdifrx_resume(struct device *dev) 1060f68c2a68SOlivier Moysan { 1061f68c2a68SOlivier Moysan struct stm32_spdifrx_data *spdifrx = dev_get_drvdata(dev); 1062f68c2a68SOlivier Moysan 1063f68c2a68SOlivier Moysan regcache_cache_only(spdifrx->regmap, false); 1064f68c2a68SOlivier Moysan 1065f68c2a68SOlivier Moysan return regcache_sync(spdifrx->regmap); 1066f68c2a68SOlivier Moysan } 1067f68c2a68SOlivier Moysan #endif /* CONFIG_PM_SLEEP */ 1068f68c2a68SOlivier Moysan 1069f68c2a68SOlivier Moysan static const struct dev_pm_ops stm32_spdifrx_pm_ops = { 1070f68c2a68SOlivier Moysan SET_SYSTEM_SLEEP_PM_OPS(stm32_spdifrx_suspend, stm32_spdifrx_resume) 1071f68c2a68SOlivier Moysan }; 1072f68c2a68SOlivier Moysan 107303e4d5d5Solivier moysan static struct platform_driver stm32_spdifrx_driver = { 107403e4d5d5Solivier moysan .driver = { 107503e4d5d5Solivier moysan .name = "st,stm32-spdifrx", 107603e4d5d5Solivier moysan .of_match_table = stm32_spdifrx_ids, 1077f68c2a68SOlivier Moysan .pm = &stm32_spdifrx_pm_ops, 107803e4d5d5Solivier moysan }, 107903e4d5d5Solivier moysan .probe = stm32_spdifrx_probe, 108003e4d5d5Solivier moysan .remove = stm32_spdifrx_remove, 108103e4d5d5Solivier moysan }; 108203e4d5d5Solivier moysan 108303e4d5d5Solivier moysan module_platform_driver(stm32_spdifrx_driver); 108403e4d5d5Solivier moysan 108503e4d5d5Solivier moysan MODULE_DESCRIPTION("STM32 Soc spdifrx Interface"); 108603e4d5d5Solivier moysan MODULE_AUTHOR("Olivier Moysan, <olivier.moysan@st.com>"); 108703e4d5d5Solivier moysan MODULE_ALIAS("platform:stm32-spdifrx"); 108803e4d5d5Solivier moysan MODULE_LICENSE("GPL v2"); 1089