18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Driver for Microchip S/PDIF RX Controller 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Author: Codrin Ciubotariu <codrin.ciubotariu@microchip.com> 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/regmap.h> 138c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <sound/dmaengine_pcm.h> 168c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 178c2ecf20Sopenharmony_ci#include <sound/soc.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * ---- S/PDIF Receiver Controller Register map ---- 218c2ecf20Sopenharmony_ci */ 228c2ecf20Sopenharmony_ci#define SPDIFRX_CR 0x00 /* Control Register */ 238c2ecf20Sopenharmony_ci#define SPDIFRX_MR 0x04 /* Mode Register */ 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define SPDIFRX_IER 0x10 /* Interrupt Enable Register */ 268c2ecf20Sopenharmony_ci#define SPDIFRX_IDR 0x14 /* Interrupt Disable Register */ 278c2ecf20Sopenharmony_ci#define SPDIFRX_IMR 0x18 /* Interrupt Mask Register */ 288c2ecf20Sopenharmony_ci#define SPDIFRX_ISR 0x1c /* Interrupt Status Register */ 298c2ecf20Sopenharmony_ci#define SPDIFRX_RSR 0x20 /* Status Register */ 308c2ecf20Sopenharmony_ci#define SPDIFRX_RHR 0x24 /* Holding Register */ 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#define SPDIFRX_CHSR(channel, reg) \ 338c2ecf20Sopenharmony_ci (0x30 + (channel) * 0x30 + (reg) * 4) /* Channel x Status Registers */ 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define SPDIFRX_CHUD(channel, reg) \ 368c2ecf20Sopenharmony_ci (0x48 + (channel) * 0x30 + (reg) * 4) /* Channel x User Data Registers */ 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define SPDIFRX_WPMR 0xE4 /* Write Protection Mode Register */ 398c2ecf20Sopenharmony_ci#define SPDIFRX_WPSR 0xE8 /* Write Protection Status Register */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define SPDIFRX_VERSION 0xFC /* Version Register */ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* 448c2ecf20Sopenharmony_ci * ---- Control Register (Write-only) ---- 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci#define SPDIFRX_CR_SWRST BIT(0) /* Software Reset */ 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * ---- Mode Register (Read/Write) ---- 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci/* Receive Enable */ 528c2ecf20Sopenharmony_ci#define SPDIFRX_MR_RXEN_MASK GENMASK(0, 0) 538c2ecf20Sopenharmony_ci#define SPDIFRX_MR_RXEN_DISABLE (0 << 0) /* SPDIF Receiver Disabled */ 548c2ecf20Sopenharmony_ci#define SPDIFRX_MR_RXEN_ENABLE (1 << 0) /* SPDIF Receiver Enabled */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* Validity Bit Mode */ 578c2ecf20Sopenharmony_ci#define SPDIFRX_MR_VBMODE_MASK GENAMSK(1, 1) 588c2ecf20Sopenharmony_ci#define SPDIFRX_MR_VBMODE_ALWAYS_LOAD \ 598c2ecf20Sopenharmony_ci (0 << 1) /* Load sample regardless of validity bit value */ 608c2ecf20Sopenharmony_ci#define SPDIFRX_MR_VBMODE_DISCARD_IF_VB1 \ 618c2ecf20Sopenharmony_ci (1 << 1) /* Load sample only if validity bit is 0 */ 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* Data Word Endian Mode */ 648c2ecf20Sopenharmony_ci#define SPDIFRX_MR_ENDIAN_MASK GENMASK(2, 2) 658c2ecf20Sopenharmony_ci#define SPDIFRX_MR_ENDIAN_LITTLE (0 << 2) /* Little Endian Mode */ 668c2ecf20Sopenharmony_ci#define SPDIFRX_MR_ENDIAN_BIG (1 << 2) /* Big Endian Mode */ 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci/* Parity Bit Mode */ 698c2ecf20Sopenharmony_ci#define SPDIFRX_MR_PBMODE_MASK GENMASK(3, 3) 708c2ecf20Sopenharmony_ci#define SPDIFRX_MR_PBMODE_PARCHECK (0 << 3) /* Parity Check Enabled */ 718c2ecf20Sopenharmony_ci#define SPDIFRX_MR_PBMODE_NOPARCHECK (1 << 3) /* Parity Check Disabled */ 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* Sample Data Width */ 748c2ecf20Sopenharmony_ci#define SPDIFRX_MR_DATAWIDTH_MASK GENMASK(5, 4) 758c2ecf20Sopenharmony_ci#define SPDIFRX_MR_DATAWIDTH(width) \ 768c2ecf20Sopenharmony_ci (((6 - (width) / 4) << 4) & SPDIFRX_MR_DATAWIDTH_MASK) 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* Packed Data Mode in Receive Holding Register */ 798c2ecf20Sopenharmony_ci#define SPDIFRX_MR_PACK_MASK GENMASK(7, 7) 808c2ecf20Sopenharmony_ci#define SPDIFRX_MR_PACK_DISABLED (0 << 7) 818c2ecf20Sopenharmony_ci#define SPDIFRX_MR_PACK_ENABLED (1 << 7) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* Start of Block Bit Mode */ 848c2ecf20Sopenharmony_ci#define SPDIFRX_MR_SBMODE_MASK GENMASK(8, 8) 858c2ecf20Sopenharmony_ci#define SPDIFRX_MR_SBMODE_ALWAYS_LOAD (0 << 8) 868c2ecf20Sopenharmony_ci#define SPDIFRX_MR_SBMODE_DISCARD (1 << 8) 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci/* Consecutive Preamble Error Threshold Automatic Restart */ 898c2ecf20Sopenharmony_ci#define SPDIFRX_MR_AUTORST_MASK GENMASK(24, 24) 908c2ecf20Sopenharmony_ci#define SPDIFRX_MR_AUTORST_NOACTION (0 << 24) 918c2ecf20Sopenharmony_ci#define SPDIFRX_MR_AUTORST_UNLOCK_ON_PRE_ERR (1 << 24) 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci/* 948c2ecf20Sopenharmony_ci * ---- Interrupt Enable/Disable/Mask/Status Register (Write/Read-only) ---- 958c2ecf20Sopenharmony_ci */ 968c2ecf20Sopenharmony_ci#define SPDIFRX_IR_RXRDY BIT(0) 978c2ecf20Sopenharmony_ci#define SPDIFRX_IR_LOCKED BIT(1) 988c2ecf20Sopenharmony_ci#define SPDIFRX_IR_LOSS BIT(2) 998c2ecf20Sopenharmony_ci#define SPDIFRX_IR_BLOCKEND BIT(3) 1008c2ecf20Sopenharmony_ci#define SPDIFRX_IR_SFE BIT(4) 1018c2ecf20Sopenharmony_ci#define SPDIFRX_IR_PAR_ERR BIT(5) 1028c2ecf20Sopenharmony_ci#define SPDIFRX_IR_OVERRUN BIT(6) 1038c2ecf20Sopenharmony_ci#define SPDIFRX_IR_RXFULL BIT(7) 1048c2ecf20Sopenharmony_ci#define SPDIFRX_IR_CSC(ch) BIT((ch) + 8) 1058c2ecf20Sopenharmony_ci#define SPDIFRX_IR_SECE BIT(10) 1068c2ecf20Sopenharmony_ci#define SPDIFRX_IR_BLOCKST BIT(11) 1078c2ecf20Sopenharmony_ci#define SPDIFRX_IR_NRZ_ERR BIT(12) 1088c2ecf20Sopenharmony_ci#define SPDIFRX_IR_PRE_ERR BIT(13) 1098c2ecf20Sopenharmony_ci#define SPDIFRX_IR_CP_ERR BIT(14) 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci/* 1128c2ecf20Sopenharmony_ci * ---- Receiver Status Register (Read/Write) ---- 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci/* Enable Status */ 1158c2ecf20Sopenharmony_ci#define SPDIFRX_RSR_ULOCK BIT(0) 1168c2ecf20Sopenharmony_ci#define SPDIFRX_RSR_BADF BIT(1) 1178c2ecf20Sopenharmony_ci#define SPDIFRX_RSR_LOWF BIT(2) 1188c2ecf20Sopenharmony_ci#define SPDIFRX_RSR_NOSIGNAL BIT(3) 1198c2ecf20Sopenharmony_ci#define SPDIFRX_RSR_IFS_MASK GENMASK(27, 16) 1208c2ecf20Sopenharmony_ci#define SPDIFRX_RSR_IFS(reg) \ 1218c2ecf20Sopenharmony_ci (((reg) & SPDIFRX_RSR_IFS_MASK) >> 16) 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/* 1248c2ecf20Sopenharmony_ci * ---- Version Register (Read-only) ---- 1258c2ecf20Sopenharmony_ci */ 1268c2ecf20Sopenharmony_ci#define SPDIFRX_VERSION_MASK GENMASK(11, 0) 1278c2ecf20Sopenharmony_ci#define SPDIFRX_VERSION_MFN_MASK GENMASK(18, 16) 1288c2ecf20Sopenharmony_ci#define SPDIFRX_VERSION_MFN(reg) (((reg) & SPDIFRX_VERSION_MFN_MASK) >> 16) 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic bool mchp_spdifrx_readable_reg(struct device *dev, unsigned int reg) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci switch (reg) { 1338c2ecf20Sopenharmony_ci case SPDIFRX_MR: 1348c2ecf20Sopenharmony_ci case SPDIFRX_IMR: 1358c2ecf20Sopenharmony_ci case SPDIFRX_ISR: 1368c2ecf20Sopenharmony_ci case SPDIFRX_RSR: 1378c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(0, 0): 1388c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(0, 1): 1398c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(0, 2): 1408c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(0, 3): 1418c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(0, 4): 1428c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(0, 5): 1438c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(0, 0): 1448c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(0, 1): 1458c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(0, 2): 1468c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(0, 3): 1478c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(0, 4): 1488c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(0, 5): 1498c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(1, 0): 1508c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(1, 1): 1518c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(1, 2): 1528c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(1, 3): 1538c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(1, 4): 1548c2ecf20Sopenharmony_ci case SPDIFRX_CHSR(1, 5): 1558c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(1, 0): 1568c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(1, 1): 1578c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(1, 2): 1588c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(1, 3): 1598c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(1, 4): 1608c2ecf20Sopenharmony_ci case SPDIFRX_CHUD(1, 5): 1618c2ecf20Sopenharmony_ci case SPDIFRX_WPMR: 1628c2ecf20Sopenharmony_ci case SPDIFRX_WPSR: 1638c2ecf20Sopenharmony_ci case SPDIFRX_VERSION: 1648c2ecf20Sopenharmony_ci return true; 1658c2ecf20Sopenharmony_ci default: 1668c2ecf20Sopenharmony_ci return false; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic bool mchp_spdifrx_writeable_reg(struct device *dev, unsigned int reg) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci switch (reg) { 1738c2ecf20Sopenharmony_ci case SPDIFRX_CR: 1748c2ecf20Sopenharmony_ci case SPDIFRX_MR: 1758c2ecf20Sopenharmony_ci case SPDIFRX_IER: 1768c2ecf20Sopenharmony_ci case SPDIFRX_IDR: 1778c2ecf20Sopenharmony_ci case SPDIFRX_WPMR: 1788c2ecf20Sopenharmony_ci return true; 1798c2ecf20Sopenharmony_ci default: 1808c2ecf20Sopenharmony_ci return false; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic bool mchp_spdifrx_precious_reg(struct device *dev, unsigned int reg) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci switch (reg) { 1878c2ecf20Sopenharmony_ci case SPDIFRX_ISR: 1888c2ecf20Sopenharmony_ci case SPDIFRX_RHR: 1898c2ecf20Sopenharmony_ci return true; 1908c2ecf20Sopenharmony_ci default: 1918c2ecf20Sopenharmony_ci return false; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci} 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_cistatic const struct regmap_config mchp_spdifrx_regmap_config = { 1968c2ecf20Sopenharmony_ci .reg_bits = 32, 1978c2ecf20Sopenharmony_ci .reg_stride = 4, 1988c2ecf20Sopenharmony_ci .val_bits = 32, 1998c2ecf20Sopenharmony_ci .max_register = SPDIFRX_VERSION, 2008c2ecf20Sopenharmony_ci .readable_reg = mchp_spdifrx_readable_reg, 2018c2ecf20Sopenharmony_ci .writeable_reg = mchp_spdifrx_writeable_reg, 2028c2ecf20Sopenharmony_ci .precious_reg = mchp_spdifrx_precious_reg, 2038c2ecf20Sopenharmony_ci}; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci#define SPDIFRX_GCLK_RATIO_MIN (12 * 64) 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci#define SPDIFRX_CS_BITS 192 2088c2ecf20Sopenharmony_ci#define SPDIFRX_UD_BITS 192 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci#define SPDIFRX_CHANNELS 2 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistruct mchp_spdifrx_ch_stat { 2138c2ecf20Sopenharmony_ci unsigned char data[SPDIFRX_CS_BITS / 8]; 2148c2ecf20Sopenharmony_ci struct completion done; 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistruct mchp_spdifrx_user_data { 2188c2ecf20Sopenharmony_ci unsigned char data[SPDIFRX_UD_BITS / 8]; 2198c2ecf20Sopenharmony_ci struct completion done; 2208c2ecf20Sopenharmony_ci}; 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_cistruct mchp_spdifrx_mixer_control { 2238c2ecf20Sopenharmony_ci struct mchp_spdifrx_ch_stat ch_stat[SPDIFRX_CHANNELS]; 2248c2ecf20Sopenharmony_ci struct mchp_spdifrx_user_data user_data[SPDIFRX_CHANNELS]; 2258c2ecf20Sopenharmony_ci bool ulock; 2268c2ecf20Sopenharmony_ci bool badf; 2278c2ecf20Sopenharmony_ci bool signal; 2288c2ecf20Sopenharmony_ci}; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistruct mchp_spdifrx_dev { 2318c2ecf20Sopenharmony_ci struct snd_dmaengine_dai_dma_data capture; 2328c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control control; 2338c2ecf20Sopenharmony_ci struct mutex mlock; 2348c2ecf20Sopenharmony_ci struct device *dev; 2358c2ecf20Sopenharmony_ci struct regmap *regmap; 2368c2ecf20Sopenharmony_ci struct clk *pclk; 2378c2ecf20Sopenharmony_ci struct clk *gclk; 2388c2ecf20Sopenharmony_ci unsigned int fmt; 2398c2ecf20Sopenharmony_ci unsigned int trigger_enabled; 2408c2ecf20Sopenharmony_ci unsigned int gclk_enabled:1; 2418c2ecf20Sopenharmony_ci}; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic void mchp_spdifrx_channel_status_read(struct mchp_spdifrx_dev *dev, 2448c2ecf20Sopenharmony_ci int channel) 2458c2ecf20Sopenharmony_ci{ 2468c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 2478c2ecf20Sopenharmony_ci u8 *ch_stat = &ctrl->ch_stat[channel].data[0]; 2488c2ecf20Sopenharmony_ci u32 val; 2498c2ecf20Sopenharmony_ci int i; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrl->ch_stat[channel].data) / 4; i++) { 2528c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_CHSR(channel, i), &val); 2538c2ecf20Sopenharmony_ci *ch_stat++ = val & 0xFF; 2548c2ecf20Sopenharmony_ci *ch_stat++ = (val >> 8) & 0xFF; 2558c2ecf20Sopenharmony_ci *ch_stat++ = (val >> 16) & 0xFF; 2568c2ecf20Sopenharmony_ci *ch_stat++ = (val >> 24) & 0xFF; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic void mchp_spdifrx_channel_user_data_read(struct mchp_spdifrx_dev *dev, 2618c2ecf20Sopenharmony_ci int channel) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 2648c2ecf20Sopenharmony_ci u8 *user_data = &ctrl->user_data[channel].data[0]; 2658c2ecf20Sopenharmony_ci u32 val; 2668c2ecf20Sopenharmony_ci int i; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ctrl->user_data[channel].data) / 4; i++) { 2698c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_CHUD(channel, i), &val); 2708c2ecf20Sopenharmony_ci *user_data++ = val & 0xFF; 2718c2ecf20Sopenharmony_ci *user_data++ = (val >> 8) & 0xFF; 2728c2ecf20Sopenharmony_ci *user_data++ = (val >> 16) & 0xFF; 2738c2ecf20Sopenharmony_ci *user_data++ = (val >> 24) & 0xFF; 2748c2ecf20Sopenharmony_ci } 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic irqreturn_t mchp_spdif_interrupt(int irq, void *dev_id) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = dev_id; 2808c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 2818c2ecf20Sopenharmony_ci u32 sr, imr, pending; 2828c2ecf20Sopenharmony_ci irqreturn_t ret = IRQ_NONE; 2838c2ecf20Sopenharmony_ci int ch; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_ISR, &sr); 2868c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_IMR, &imr); 2878c2ecf20Sopenharmony_ci pending = sr & imr; 2888c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "ISR: %#x, IMR: %#x, pending: %#x\n", sr, imr, 2898c2ecf20Sopenharmony_ci pending); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci if (!pending) 2928c2ecf20Sopenharmony_ci return IRQ_NONE; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci if (pending & SPDIFRX_IR_BLOCKEND) { 2958c2ecf20Sopenharmony_ci for (ch = 0; ch < SPDIFRX_CHANNELS; ch++) { 2968c2ecf20Sopenharmony_ci mchp_spdifrx_channel_user_data_read(dev, ch); 2978c2ecf20Sopenharmony_ci complete(&ctrl->user_data[ch].done); 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND); 3008c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 3018c2ecf20Sopenharmony_ci } 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci for (ch = 0; ch < SPDIFRX_CHANNELS; ch++) { 3048c2ecf20Sopenharmony_ci if (pending & SPDIFRX_IR_CSC(ch)) { 3058c2ecf20Sopenharmony_ci mchp_spdifrx_channel_status_read(dev, ch); 3068c2ecf20Sopenharmony_ci complete(&ctrl->ch_stat[ch].done); 3078c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_CSC(ch)); 3088c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci } 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (pending & SPDIFRX_IR_OVERRUN) { 3138c2ecf20Sopenharmony_ci dev_warn(dev->dev, "Overrun detected\n"); 3148c2ecf20Sopenharmony_ci ret = IRQ_HANDLED; 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return ret; 3188c2ecf20Sopenharmony_ci} 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_cistatic int mchp_spdifrx_trigger(struct snd_pcm_substream *substream, int cmd, 3218c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 3248c2ecf20Sopenharmony_ci int ret = 0; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci switch (cmd) { 3278c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 3288c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 3298c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 3308c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 3318c2ecf20Sopenharmony_ci /* Enable overrun interrupts */ 3328c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IER, SPDIFRX_IR_OVERRUN); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Enable receiver. */ 3358c2ecf20Sopenharmony_ci regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, 3368c2ecf20Sopenharmony_ci SPDIFRX_MR_RXEN_ENABLE); 3378c2ecf20Sopenharmony_ci dev->trigger_enabled = true; 3388c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3418c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 3428c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 3438c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 3448c2ecf20Sopenharmony_ci /* Disable overrun interrupts */ 3458c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_OVERRUN); 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Disable receiver. */ 3488c2ecf20Sopenharmony_ci regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, 3498c2ecf20Sopenharmony_ci SPDIFRX_MR_RXEN_DISABLE); 3508c2ecf20Sopenharmony_ci dev->trigger_enabled = false; 3518c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci default: 3548c2ecf20Sopenharmony_ci ret = -EINVAL; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return ret; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_cistatic int mchp_spdifrx_hw_params(struct snd_pcm_substream *substream, 3618c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 3628c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 3658c2ecf20Sopenharmony_ci u32 mr = 0; 3668c2ecf20Sopenharmony_ci int ret; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n", 3698c2ecf20Sopenharmony_ci __func__, params_rate(params), params_format(params), 3708c2ecf20Sopenharmony_ci params_width(params), params_channels(params)); 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { 3738c2ecf20Sopenharmony_ci dev_err(dev->dev, "Playback is not supported\n"); 3748c2ecf20Sopenharmony_ci return -EINVAL; 3758c2ecf20Sopenharmony_ci } 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (params_channels(params) != SPDIFRX_CHANNELS) { 3788c2ecf20Sopenharmony_ci dev_err(dev->dev, "unsupported number of channels: %d\n", 3798c2ecf20Sopenharmony_ci params_channels(params)); 3808c2ecf20Sopenharmony_ci return -EINVAL; 3818c2ecf20Sopenharmony_ci } 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci switch (params_format(params)) { 3848c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_BE: 3858c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3BE: 3868c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3BE: 3878c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_BE: 3888c2ecf20Sopenharmony_ci mr |= SPDIFRX_MR_ENDIAN_BIG; 3898c2ecf20Sopenharmony_ci fallthrough; 3908c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S16_LE: 3918c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S20_3LE: 3928c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_3LE: 3938c2ecf20Sopenharmony_ci case SNDRV_PCM_FORMAT_S24_LE: 3948c2ecf20Sopenharmony_ci mr |= SPDIFRX_MR_DATAWIDTH(params_width(params)); 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci default: 3978c2ecf20Sopenharmony_ci dev_err(dev->dev, "unsupported PCM format: %d\n", 3988c2ecf20Sopenharmony_ci params_format(params)); 3998c2ecf20Sopenharmony_ci return -EINVAL; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 4038c2ecf20Sopenharmony_ci if (dev->trigger_enabled) { 4048c2ecf20Sopenharmony_ci dev_err(dev->dev, "PCM already running\n"); 4058c2ecf20Sopenharmony_ci ret = -EBUSY; 4068c2ecf20Sopenharmony_ci goto unlock; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci if (dev->gclk_enabled) { 4108c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->gclk); 4118c2ecf20Sopenharmony_ci dev->gclk_enabled = 0; 4128c2ecf20Sopenharmony_ci } 4138c2ecf20Sopenharmony_ci ret = clk_set_min_rate(dev->gclk, params_rate(params) * 4148c2ecf20Sopenharmony_ci SPDIFRX_GCLK_RATIO_MIN + 1); 4158c2ecf20Sopenharmony_ci if (ret) { 4168c2ecf20Sopenharmony_ci dev_err(dev->dev, 4178c2ecf20Sopenharmony_ci "unable to set gclk min rate: rate %u * ratio %u + 1\n", 4188c2ecf20Sopenharmony_ci params_rate(params), SPDIFRX_GCLK_RATIO_MIN); 4198c2ecf20Sopenharmony_ci goto unlock; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->gclk); 4228c2ecf20Sopenharmony_ci if (ret) { 4238c2ecf20Sopenharmony_ci dev_err(dev->dev, "unable to enable gclk: %d\n", ret); 4248c2ecf20Sopenharmony_ci goto unlock; 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci dev->gclk_enabled = 1; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "GCLK range min set to %d\n", 4298c2ecf20Sopenharmony_ci params_rate(params) * SPDIFRX_GCLK_RATIO_MIN + 1); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci ret = regmap_write(dev->regmap, SPDIFRX_MR, mr); 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ciunlock: 4348c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return ret; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic int mchp_spdifrx_hw_free(struct snd_pcm_substream *substream, 4408c2ecf20Sopenharmony_ci struct snd_soc_dai *dai) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 4458c2ecf20Sopenharmony_ci if (dev->gclk_enabled) { 4468c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->gclk); 4478c2ecf20Sopenharmony_ci dev->gclk_enabled = 0; 4488c2ecf20Sopenharmony_ci } 4498c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 4508c2ecf20Sopenharmony_ci return 0; 4518c2ecf20Sopenharmony_ci} 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_cistatic const struct snd_soc_dai_ops mchp_spdifrx_dai_ops = { 4548c2ecf20Sopenharmony_ci .trigger = mchp_spdifrx_trigger, 4558c2ecf20Sopenharmony_ci .hw_params = mchp_spdifrx_hw_params, 4568c2ecf20Sopenharmony_ci .hw_free = mchp_spdifrx_hw_free, 4578c2ecf20Sopenharmony_ci}; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci#define MCHP_SPDIF_RATES SNDRV_PCM_RATE_8000_192000 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci#define MCHP_SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \ 4628c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_U16_BE | \ 4638c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3LE | \ 4648c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S20_3BE | \ 4658c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3LE | \ 4668c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_3BE | \ 4678c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_LE | \ 4688c2ecf20Sopenharmony_ci SNDRV_PCM_FMTBIT_S24_BE \ 4698c2ecf20Sopenharmony_ci ) 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_cistatic int mchp_spdifrx_info(struct snd_kcontrol *kcontrol, 4728c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 4738c2ecf20Sopenharmony_ci{ 4748c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; 4758c2ecf20Sopenharmony_ci uinfo->count = 1; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci return 0; 4788c2ecf20Sopenharmony_ci} 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_cistatic int mchp_spdifrx_cs_get(struct mchp_spdifrx_dev *dev, 4818c2ecf20Sopenharmony_ci int channel, 4828c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 4858c2ecf20Sopenharmony_ci struct mchp_spdifrx_ch_stat *ch_stat = &ctrl->ch_stat[channel]; 4868c2ecf20Sopenharmony_ci int ret = 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * We may reach this point with both clocks enabled but the receiver 4928c2ecf20Sopenharmony_ci * still disabled. To void waiting for completion and return with 4938c2ecf20Sopenharmony_ci * timeout check the dev->trigger_enabled. 4948c2ecf20Sopenharmony_ci * 4958c2ecf20Sopenharmony_ci * To retrieve data: 4968c2ecf20Sopenharmony_ci * - if the receiver is enabled CSC IRQ will update the data in software 4978c2ecf20Sopenharmony_ci * caches (ch_stat->data) 4988c2ecf20Sopenharmony_ci * - otherwise we just update it here the software caches with latest 4998c2ecf20Sopenharmony_ci * available information and return it; in this case we don't need 5008c2ecf20Sopenharmony_ci * spin locking as the IRQ is disabled and will not be raised from 5018c2ecf20Sopenharmony_ci * anywhere else. 5028c2ecf20Sopenharmony_ci */ 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (dev->trigger_enabled) { 5058c2ecf20Sopenharmony_ci reinit_completion(&ch_stat->done); 5068c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IER, SPDIFRX_IR_CSC(channel)); 5078c2ecf20Sopenharmony_ci /* Check for new data available */ 5088c2ecf20Sopenharmony_ci ret = wait_for_completion_interruptible_timeout(&ch_stat->done, 5098c2ecf20Sopenharmony_ci msecs_to_jiffies(100)); 5108c2ecf20Sopenharmony_ci /* Valid stream might not be present */ 5118c2ecf20Sopenharmony_ci if (ret <= 0) { 5128c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "channel status for channel %d timeout\n", 5138c2ecf20Sopenharmony_ci channel); 5148c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_CSC(channel)); 5158c2ecf20Sopenharmony_ci ret = ret ? : -ETIMEDOUT; 5168c2ecf20Sopenharmony_ci goto unlock; 5178c2ecf20Sopenharmony_ci } else { 5188c2ecf20Sopenharmony_ci ret = 0; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci } else { 5218c2ecf20Sopenharmony_ci /* Update software cache with latest channel status. */ 5228c2ecf20Sopenharmony_ci mchp_spdifrx_channel_status_read(dev, channel); 5238c2ecf20Sopenharmony_ci } 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci memcpy(uvalue->value.iec958.status, ch_stat->data, 5268c2ecf20Sopenharmony_ci sizeof(ch_stat->data)); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ciunlock: 5298c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 5308c2ecf20Sopenharmony_ci return ret; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cistatic int mchp_spdifrx_cs1_get(struct snd_kcontrol *kcontrol, 5348c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 5358c2ecf20Sopenharmony_ci{ 5368c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 5378c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci return mchp_spdifrx_cs_get(dev, 0, uvalue); 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int mchp_spdifrx_cs2_get(struct snd_kcontrol *kcontrol, 5438c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 5468c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return mchp_spdifrx_cs_get(dev, 1, uvalue); 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int mchp_spdifrx_cs_mask(struct snd_kcontrol *kcontrol, 5528c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci memset(uvalue->value.iec958.status, 0xff, 5558c2ecf20Sopenharmony_ci sizeof(uvalue->value.iec958.status)); 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci return 0; 5588c2ecf20Sopenharmony_ci} 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_cistatic int mchp_spdifrx_subcode_ch_get(struct mchp_spdifrx_dev *dev, 5618c2ecf20Sopenharmony_ci int channel, 5628c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 5658c2ecf20Sopenharmony_ci struct mchp_spdifrx_user_data *user_data = &ctrl->user_data[channel]; 5668c2ecf20Sopenharmony_ci int ret = 0; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci /* 5718c2ecf20Sopenharmony_ci * We may reach this point with both clocks enabled but the receiver 5728c2ecf20Sopenharmony_ci * still disabled. To void waiting for completion to just timeout we 5738c2ecf20Sopenharmony_ci * check here the dev->trigger_enabled flag. 5748c2ecf20Sopenharmony_ci * 5758c2ecf20Sopenharmony_ci * To retrieve data: 5768c2ecf20Sopenharmony_ci * - if the receiver is enabled we need to wait for blockend IRQ to read 5778c2ecf20Sopenharmony_ci * data to and update it for us in software caches 5788c2ecf20Sopenharmony_ci * - otherwise reading the SPDIFRX_CHUD() registers is enough. 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci if (dev->trigger_enabled) { 5828c2ecf20Sopenharmony_ci reinit_completion(&user_data->done); 5838c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IER, SPDIFRX_IR_BLOCKEND); 5848c2ecf20Sopenharmony_ci ret = wait_for_completion_interruptible_timeout(&user_data->done, 5858c2ecf20Sopenharmony_ci msecs_to_jiffies(100)); 5868c2ecf20Sopenharmony_ci /* Valid stream might not be present. */ 5878c2ecf20Sopenharmony_ci if (ret <= 0) { 5888c2ecf20Sopenharmony_ci dev_dbg(dev->dev, "user data for channel %d timeout\n", 5898c2ecf20Sopenharmony_ci channel); 5908c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IDR, SPDIFRX_IR_BLOCKEND); 5918c2ecf20Sopenharmony_ci ret = ret ? : -ETIMEDOUT; 5928c2ecf20Sopenharmony_ci goto unlock; 5938c2ecf20Sopenharmony_ci } else { 5948c2ecf20Sopenharmony_ci ret = 0; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci } else { 5978c2ecf20Sopenharmony_ci /* Update software cache with last available data. */ 5988c2ecf20Sopenharmony_ci mchp_spdifrx_channel_user_data_read(dev, channel); 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci memcpy(uvalue->value.iec958.subcode, user_data->data, 6028c2ecf20Sopenharmony_ci sizeof(user_data->data)); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciunlock: 6058c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 6068c2ecf20Sopenharmony_ci return ret; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int mchp_spdifrx_subcode_ch1_get(struct snd_kcontrol *kcontrol, 6108c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 6138c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return mchp_spdifrx_subcode_ch_get(dev, 0, uvalue); 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_cistatic int mchp_spdifrx_subcode_ch2_get(struct snd_kcontrol *kcontrol, 6198c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 6208c2ecf20Sopenharmony_ci{ 6218c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 6228c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci return mchp_spdifrx_subcode_ch_get(dev, 1, uvalue); 6258c2ecf20Sopenharmony_ci} 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_cistatic int mchp_spdifrx_boolean_info(struct snd_kcontrol *kcontrol, 6288c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 6298c2ecf20Sopenharmony_ci{ 6308c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 6318c2ecf20Sopenharmony_ci uinfo->count = 1; 6328c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 6338c2ecf20Sopenharmony_ci uinfo->value.integer.max = 1; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci return 0; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_cistatic int mchp_spdifrx_ulock_get(struct snd_kcontrol *kcontrol, 6398c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 6408c2ecf20Sopenharmony_ci{ 6418c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 6428c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 6438c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 6448c2ecf20Sopenharmony_ci u32 val; 6458c2ecf20Sopenharmony_ci bool ulock_old = ctrl->ulock; 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* 6508c2ecf20Sopenharmony_ci * The RSR.ULOCK has wrong value if both pclk and gclk are enabled 6518c2ecf20Sopenharmony_ci * and the receiver is disabled. Thus we take into account the 6528c2ecf20Sopenharmony_ci * dev->trigger_enabled here to return a real status. 6538c2ecf20Sopenharmony_ci */ 6548c2ecf20Sopenharmony_ci if (dev->trigger_enabled) { 6558c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_RSR, &val); 6568c2ecf20Sopenharmony_ci ctrl->ulock = !(val & SPDIFRX_RSR_ULOCK); 6578c2ecf20Sopenharmony_ci } else { 6588c2ecf20Sopenharmony_ci ctrl->ulock = 0; 6598c2ecf20Sopenharmony_ci } 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci uvalue->value.integer.value[0] = ctrl->ulock; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return ulock_old != ctrl->ulock; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic int mchp_spdifrx_badf_get(struct snd_kcontrol *kcontrol, 6698c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 6708c2ecf20Sopenharmony_ci{ 6718c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 6728c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 6738c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 6748c2ecf20Sopenharmony_ci u32 val; 6758c2ecf20Sopenharmony_ci bool badf_old = ctrl->badf; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci /* 6808c2ecf20Sopenharmony_ci * The RSR.ULOCK has wrong value if both pclk and gclk are enabled 6818c2ecf20Sopenharmony_ci * and the receiver is disabled. Thus we take into account the 6828c2ecf20Sopenharmony_ci * dev->trigger_enabled here to return a real status. 6838c2ecf20Sopenharmony_ci */ 6848c2ecf20Sopenharmony_ci if (dev->trigger_enabled) { 6858c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_RSR, &val); 6868c2ecf20Sopenharmony_ci ctrl->badf = !!(val & SPDIFRX_RSR_BADF); 6878c2ecf20Sopenharmony_ci } else { 6888c2ecf20Sopenharmony_ci ctrl->badf = 0; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci uvalue->value.integer.value[0] = ctrl->badf; 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci return badf_old != ctrl->badf; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_cistatic int mchp_spdifrx_signal_get(struct snd_kcontrol *kcontrol, 6998c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *uvalue) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 7028c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 7038c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 7048c2ecf20Sopenharmony_ci u32 val = ~0U, loops = 10; 7058c2ecf20Sopenharmony_ci int ret; 7068c2ecf20Sopenharmony_ci bool signal_old = ctrl->signal; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* 7118c2ecf20Sopenharmony_ci * To get the signal we need to have receiver enabled. This 7128c2ecf20Sopenharmony_ci * could be enabled also from trigger() function thus we need to 7138c2ecf20Sopenharmony_ci * take care of not disabling the receiver when it runs. 7148c2ecf20Sopenharmony_ci */ 7158c2ecf20Sopenharmony_ci if (!dev->trigger_enabled) { 7168c2ecf20Sopenharmony_ci ret = clk_prepare_enable(dev->gclk); 7178c2ecf20Sopenharmony_ci if (ret) 7188c2ecf20Sopenharmony_ci goto unlock; 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, 7218c2ecf20Sopenharmony_ci SPDIFRX_MR_RXEN_ENABLE); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci /* Wait for RSR.ULOCK bit. */ 7248c2ecf20Sopenharmony_ci while (--loops) { 7258c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_RSR, &val); 7268c2ecf20Sopenharmony_ci if (!(val & SPDIFRX_RSR_ULOCK)) 7278c2ecf20Sopenharmony_ci break; 7288c2ecf20Sopenharmony_ci usleep_range(100, 150); 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci regmap_update_bits(dev->regmap, SPDIFRX_MR, SPDIFRX_MR_RXEN_MASK, 7328c2ecf20Sopenharmony_ci SPDIFRX_MR_RXEN_DISABLE); 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->gclk); 7358c2ecf20Sopenharmony_ci } else { 7368c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_RSR, &val); 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ciunlock: 7408c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ci if (!(val & SPDIFRX_RSR_ULOCK)) 7438c2ecf20Sopenharmony_ci ctrl->signal = !(val & SPDIFRX_RSR_NOSIGNAL); 7448c2ecf20Sopenharmony_ci else 7458c2ecf20Sopenharmony_ci ctrl->signal = 0; 7468c2ecf20Sopenharmony_ci uvalue->value.integer.value[0] = ctrl->signal; 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return signal_old != ctrl->signal; 7498c2ecf20Sopenharmony_ci} 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_cistatic int mchp_spdifrx_rate_info(struct snd_kcontrol *kcontrol, 7528c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *uinfo) 7538c2ecf20Sopenharmony_ci{ 7548c2ecf20Sopenharmony_ci uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 7558c2ecf20Sopenharmony_ci uinfo->count = 1; 7568c2ecf20Sopenharmony_ci uinfo->value.integer.min = 0; 7578c2ecf20Sopenharmony_ci uinfo->value.integer.max = 192000; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return 0; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int mchp_spdifrx_rate_get(struct snd_kcontrol *kcontrol, 7638c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *ucontrol) 7648c2ecf20Sopenharmony_ci{ 7658c2ecf20Sopenharmony_ci struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); 7668c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 7678c2ecf20Sopenharmony_ci u32 val; 7688c2ecf20Sopenharmony_ci int rate; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci mutex_lock(&dev->mlock); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci /* 7738c2ecf20Sopenharmony_ci * The RSR.ULOCK has wrong value if both pclk and gclk are enabled 7748c2ecf20Sopenharmony_ci * and the receiver is disabled. Thus we take into account the 7758c2ecf20Sopenharmony_ci * dev->trigger_enabled here to return a real status. 7768c2ecf20Sopenharmony_ci */ 7778c2ecf20Sopenharmony_ci if (dev->trigger_enabled) { 7788c2ecf20Sopenharmony_ci regmap_read(dev->regmap, SPDIFRX_RSR, &val); 7798c2ecf20Sopenharmony_ci /* If the receiver is not locked, ISF data is invalid. */ 7808c2ecf20Sopenharmony_ci if (val & SPDIFRX_RSR_ULOCK || !(val & SPDIFRX_RSR_IFS_MASK)) { 7818c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0; 7828c2ecf20Sopenharmony_ci goto unlock; 7838c2ecf20Sopenharmony_ci } 7848c2ecf20Sopenharmony_ci } else { 7858c2ecf20Sopenharmony_ci /* Reveicer is not locked, IFS data is invalid. */ 7868c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = 0; 7878c2ecf20Sopenharmony_ci goto unlock; 7888c2ecf20Sopenharmony_ci } 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci rate = clk_get_rate(dev->gclk); 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ucontrol->value.integer.value[0] = rate / (32 * SPDIFRX_RSR_IFS(val)); 7938c2ecf20Sopenharmony_ci 7948c2ecf20Sopenharmony_ciunlock: 7958c2ecf20Sopenharmony_ci mutex_unlock(&dev->mlock); 7968c2ecf20Sopenharmony_ci return 0; 7978c2ecf20Sopenharmony_ci} 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_cistatic struct snd_kcontrol_new mchp_spdifrx_ctrls[] = { 8008c2ecf20Sopenharmony_ci /* Channel status controller */ 8018c2ecf20Sopenharmony_ci { 8028c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8038c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT) 8048c2ecf20Sopenharmony_ci " Channel 1", 8058c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8068c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8078c2ecf20Sopenharmony_ci .info = mchp_spdifrx_info, 8088c2ecf20Sopenharmony_ci .get = mchp_spdifrx_cs1_get, 8098c2ecf20Sopenharmony_ci }, 8108c2ecf20Sopenharmony_ci { 8118c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8128c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT) 8138c2ecf20Sopenharmony_ci " Channel 2", 8148c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8158c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8168c2ecf20Sopenharmony_ci .info = mchp_spdifrx_info, 8178c2ecf20Sopenharmony_ci .get = mchp_spdifrx_cs2_get, 8188c2ecf20Sopenharmony_ci }, 8198c2ecf20Sopenharmony_ci { 8208c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8218c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), 8228c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ, 8238c2ecf20Sopenharmony_ci .info = mchp_spdifrx_info, 8248c2ecf20Sopenharmony_ci .get = mchp_spdifrx_cs_mask, 8258c2ecf20Sopenharmony_ci }, 8268c2ecf20Sopenharmony_ci /* User bits controller */ 8278c2ecf20Sopenharmony_ci { 8288c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8298c2ecf20Sopenharmony_ci .name = "IEC958 Subcode Capture Default Channel 1", 8308c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8318c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8328c2ecf20Sopenharmony_ci .info = mchp_spdifrx_info, 8338c2ecf20Sopenharmony_ci .get = mchp_spdifrx_subcode_ch1_get, 8348c2ecf20Sopenharmony_ci }, 8358c2ecf20Sopenharmony_ci { 8368c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8378c2ecf20Sopenharmony_ci .name = "IEC958 Subcode Capture Default Channel 2", 8388c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8398c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8408c2ecf20Sopenharmony_ci .info = mchp_spdifrx_info, 8418c2ecf20Sopenharmony_ci .get = mchp_spdifrx_subcode_ch2_get, 8428c2ecf20Sopenharmony_ci }, 8438c2ecf20Sopenharmony_ci /* Lock status */ 8448c2ecf20Sopenharmony_ci { 8458c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8468c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Unlocked", 8478c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8488c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8498c2ecf20Sopenharmony_ci .info = mchp_spdifrx_boolean_info, 8508c2ecf20Sopenharmony_ci .get = mchp_spdifrx_ulock_get, 8518c2ecf20Sopenharmony_ci }, 8528c2ecf20Sopenharmony_ci /* Bad format */ 8538c2ecf20Sopenharmony_ci { 8548c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8558c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE)"Bad Format", 8568c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8578c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8588c2ecf20Sopenharmony_ci .info = mchp_spdifrx_boolean_info, 8598c2ecf20Sopenharmony_ci .get = mchp_spdifrx_badf_get, 8608c2ecf20Sopenharmony_ci }, 8618c2ecf20Sopenharmony_ci /* Signal */ 8628c2ecf20Sopenharmony_ci { 8638c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8648c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Signal", 8658c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8668c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8678c2ecf20Sopenharmony_ci .info = mchp_spdifrx_boolean_info, 8688c2ecf20Sopenharmony_ci .get = mchp_spdifrx_signal_get, 8698c2ecf20Sopenharmony_ci }, 8708c2ecf20Sopenharmony_ci /* Sampling rate */ 8718c2ecf20Sopenharmony_ci { 8728c2ecf20Sopenharmony_ci .iface = SNDRV_CTL_ELEM_IFACE_PCM, 8738c2ecf20Sopenharmony_ci .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, NONE) "Rate", 8748c2ecf20Sopenharmony_ci .access = SNDRV_CTL_ELEM_ACCESS_READ | 8758c2ecf20Sopenharmony_ci SNDRV_CTL_ELEM_ACCESS_VOLATILE, 8768c2ecf20Sopenharmony_ci .info = mchp_spdifrx_rate_info, 8778c2ecf20Sopenharmony_ci .get = mchp_spdifrx_rate_get, 8788c2ecf20Sopenharmony_ci }, 8798c2ecf20Sopenharmony_ci}; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_cistatic int mchp_spdifrx_dai_probe(struct snd_soc_dai *dai) 8828c2ecf20Sopenharmony_ci{ 8838c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 8848c2ecf20Sopenharmony_ci struct mchp_spdifrx_mixer_control *ctrl = &dev->control; 8858c2ecf20Sopenharmony_ci int ch; 8868c2ecf20Sopenharmony_ci int err; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci err = clk_prepare_enable(dev->pclk); 8898c2ecf20Sopenharmony_ci if (err) { 8908c2ecf20Sopenharmony_ci dev_err(dev->dev, 8918c2ecf20Sopenharmony_ci "failed to enable the peripheral clock: %d\n", err); 8928c2ecf20Sopenharmony_ci return err; 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci snd_soc_dai_init_dma_data(dai, NULL, &dev->capture); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci /* Software reset the IP */ 8988c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_CR, SPDIFRX_CR_SWRST); 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci /* Default configuration */ 9018c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_MR, 9028c2ecf20Sopenharmony_ci SPDIFRX_MR_VBMODE_DISCARD_IF_VB1 | 9038c2ecf20Sopenharmony_ci SPDIFRX_MR_SBMODE_DISCARD | 9048c2ecf20Sopenharmony_ci SPDIFRX_MR_AUTORST_NOACTION | 9058c2ecf20Sopenharmony_ci SPDIFRX_MR_PACK_DISABLED); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci for (ch = 0; ch < SPDIFRX_CHANNELS; ch++) { 9088c2ecf20Sopenharmony_ci init_completion(&ctrl->ch_stat[ch].done); 9098c2ecf20Sopenharmony_ci init_completion(&ctrl->user_data[ch].done); 9108c2ecf20Sopenharmony_ci } 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci /* Add controls */ 9138c2ecf20Sopenharmony_ci snd_soc_add_dai_controls(dai, mchp_spdifrx_ctrls, 9148c2ecf20Sopenharmony_ci ARRAY_SIZE(mchp_spdifrx_ctrls)); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return 0; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic int mchp_spdifrx_dai_remove(struct snd_soc_dai *dai) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev = snd_soc_dai_get_drvdata(dai); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci /* Disable interrupts */ 9248c2ecf20Sopenharmony_ci regmap_write(dev->regmap, SPDIFRX_IDR, GENMASK(14, 0)); 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci clk_disable_unprepare(dev->pclk); 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic struct snd_soc_dai_driver mchp_spdifrx_dai = { 9328c2ecf20Sopenharmony_ci .name = "mchp-spdifrx", 9338c2ecf20Sopenharmony_ci .probe = mchp_spdifrx_dai_probe, 9348c2ecf20Sopenharmony_ci .remove = mchp_spdifrx_dai_remove, 9358c2ecf20Sopenharmony_ci .capture = { 9368c2ecf20Sopenharmony_ci .stream_name = "S/PDIF Capture", 9378c2ecf20Sopenharmony_ci .channels_min = SPDIFRX_CHANNELS, 9388c2ecf20Sopenharmony_ci .channels_max = SPDIFRX_CHANNELS, 9398c2ecf20Sopenharmony_ci .rates = MCHP_SPDIF_RATES, 9408c2ecf20Sopenharmony_ci .formats = MCHP_SPDIF_FORMATS, 9418c2ecf20Sopenharmony_ci }, 9428c2ecf20Sopenharmony_ci .ops = &mchp_spdifrx_dai_ops, 9438c2ecf20Sopenharmony_ci}; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic const struct snd_soc_component_driver mchp_spdifrx_component = { 9468c2ecf20Sopenharmony_ci .name = "mchp-spdifrx", 9478c2ecf20Sopenharmony_ci}; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_cistatic const struct of_device_id mchp_spdifrx_dt_ids[] = { 9508c2ecf20Sopenharmony_ci { 9518c2ecf20Sopenharmony_ci .compatible = "microchip,sama7g5-spdifrx", 9528c2ecf20Sopenharmony_ci }, 9538c2ecf20Sopenharmony_ci { /* sentinel */ } 9548c2ecf20Sopenharmony_ci}; 9558c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, mchp_spdifrx_dt_ids); 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_cistatic int mchp_spdifrx_probe(struct platform_device *pdev) 9588c2ecf20Sopenharmony_ci{ 9598c2ecf20Sopenharmony_ci struct mchp_spdifrx_dev *dev; 9608c2ecf20Sopenharmony_ci struct resource *mem; 9618c2ecf20Sopenharmony_ci struct regmap *regmap; 9628c2ecf20Sopenharmony_ci void __iomem *base; 9638c2ecf20Sopenharmony_ci int irq; 9648c2ecf20Sopenharmony_ci int err; 9658c2ecf20Sopenharmony_ci u32 vers; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Get memory for driver data. */ 9688c2ecf20Sopenharmony_ci dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); 9698c2ecf20Sopenharmony_ci if (!dev) 9708c2ecf20Sopenharmony_ci return -ENOMEM; 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci /* Map I/O registers. */ 9738c2ecf20Sopenharmony_ci base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); 9748c2ecf20Sopenharmony_ci if (IS_ERR(base)) 9758c2ecf20Sopenharmony_ci return PTR_ERR(base); 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci regmap = devm_regmap_init_mmio(&pdev->dev, base, 9788c2ecf20Sopenharmony_ci &mchp_spdifrx_regmap_config); 9798c2ecf20Sopenharmony_ci if (IS_ERR(regmap)) 9808c2ecf20Sopenharmony_ci return PTR_ERR(regmap); 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci /* Request IRQ. */ 9838c2ecf20Sopenharmony_ci irq = platform_get_irq(pdev, 0); 9848c2ecf20Sopenharmony_ci if (irq < 0) 9858c2ecf20Sopenharmony_ci return irq; 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci err = devm_request_irq(&pdev->dev, irq, mchp_spdif_interrupt, 0, 9888c2ecf20Sopenharmony_ci dev_name(&pdev->dev), dev); 9898c2ecf20Sopenharmony_ci if (err) 9908c2ecf20Sopenharmony_ci return err; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci /* Get the peripheral clock */ 9938c2ecf20Sopenharmony_ci dev->pclk = devm_clk_get(&pdev->dev, "pclk"); 9948c2ecf20Sopenharmony_ci if (IS_ERR(dev->pclk)) { 9958c2ecf20Sopenharmony_ci err = PTR_ERR(dev->pclk); 9968c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to get the peripheral clock: %d\n", 9978c2ecf20Sopenharmony_ci err); 9988c2ecf20Sopenharmony_ci return err; 9998c2ecf20Sopenharmony_ci } 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci /* Get the generated clock */ 10028c2ecf20Sopenharmony_ci dev->gclk = devm_clk_get(&pdev->dev, "gclk"); 10038c2ecf20Sopenharmony_ci if (IS_ERR(dev->gclk)) { 10048c2ecf20Sopenharmony_ci err = PTR_ERR(dev->gclk); 10058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, 10068c2ecf20Sopenharmony_ci "failed to get the PMC generated clock: %d\n", err); 10078c2ecf20Sopenharmony_ci return err; 10088c2ecf20Sopenharmony_ci } 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* 10118c2ecf20Sopenharmony_ci * Signal control need a valid rate on gclk. hw_params() configures 10128c2ecf20Sopenharmony_ci * it propertly but requesting signal before any hw_params() has been 10138c2ecf20Sopenharmony_ci * called lead to invalid value returned for signal. Thus, configure 10148c2ecf20Sopenharmony_ci * gclk at a valid rate, here, in initialization, to simplify the 10158c2ecf20Sopenharmony_ci * control path. 10168c2ecf20Sopenharmony_ci */ 10178c2ecf20Sopenharmony_ci clk_set_min_rate(dev->gclk, 48000 * SPDIFRX_GCLK_RATIO_MIN + 1); 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci mutex_init(&dev->mlock); 10208c2ecf20Sopenharmony_ci 10218c2ecf20Sopenharmony_ci dev->dev = &pdev->dev; 10228c2ecf20Sopenharmony_ci dev->regmap = regmap; 10238c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, dev); 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci dev->capture.addr = (dma_addr_t)mem->start + SPDIFRX_RHR; 10268c2ecf20Sopenharmony_ci dev->capture.maxburst = 1; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci err = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); 10298c2ecf20Sopenharmony_ci if (err) { 10308c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "failed to register PMC: %d\n", err); 10318c2ecf20Sopenharmony_ci return err; 10328c2ecf20Sopenharmony_ci } 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci err = devm_snd_soc_register_component(&pdev->dev, 10358c2ecf20Sopenharmony_ci &mchp_spdifrx_component, 10368c2ecf20Sopenharmony_ci &mchp_spdifrx_dai, 1); 10378c2ecf20Sopenharmony_ci if (err) { 10388c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "fail to register dai\n"); 10398c2ecf20Sopenharmony_ci return err; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci regmap_read(regmap, SPDIFRX_VERSION, &vers); 10438c2ecf20Sopenharmony_ci dev_info(&pdev->dev, "hw version: %#lx\n", vers & SPDIFRX_VERSION_MASK); 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci} 10478c2ecf20Sopenharmony_ci 10488c2ecf20Sopenharmony_cistatic struct platform_driver mchp_spdifrx_driver = { 10498c2ecf20Sopenharmony_ci .probe = mchp_spdifrx_probe, 10508c2ecf20Sopenharmony_ci .driver = { 10518c2ecf20Sopenharmony_ci .name = "mchp_spdifrx", 10528c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(mchp_spdifrx_dt_ids), 10538c2ecf20Sopenharmony_ci }, 10548c2ecf20Sopenharmony_ci}; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_cimodule_platform_driver(mchp_spdifrx_driver); 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ciMODULE_AUTHOR("Codrin Ciubotariu <codrin.ciubotariu@microchip.com>"); 10598c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Microchip S/PDIF RX Controller Driver"); 10608c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1061