From eae70e5ad3cfbe074db7893b945091d3dea724b3 Mon Sep 17 00:00:00 2001 From: Zhong Shengquan Date: Tue, 18 Feb 2025 16:25:26 +0800 Subject: [PATCH] ASoC: rockchip: spdifrx: Update the dynamic detection feature Add a debounce timer to prevent continuous reporting of SYNC/NSYNC information during plug-in and unplug operations. Add the capability to detect non-linear pcm data and sample bit width, then notify the application layer of the results. Add a fifo timer to detect real-time data inflow in the rx fifo, supporting glitch-free sampling rate transitions. Add a configuration option for the always-on clock feature. Change-Id: Ifb7bd55e9eefb6e07d00e16de12abff43d7e4d4e Signed-off-by: Zhong Shengquan --- sound/soc/rockchip/rockchip_spdifrx.c | 506 ++++++++++++++++++++++++-- sound/soc/rockchip/rockchip_spdifrx.h | 44 ++- 2 files changed, 523 insertions(+), 27 deletions(-) diff --git a/sound/soc/rockchip/rockchip_spdifrx.c b/sound/soc/rockchip/rockchip_spdifrx.c index e95e85243767..066de3a388c0 100644 --- a/sound/soc/rockchip/rockchip_spdifrx.c +++ b/sound/soc/rockchip/rockchip_spdifrx.c @@ -6,24 +6,35 @@ * */ -#include -#include -#include #include -#include +#include +#include #include +#include +#include +#include #include #include +#include #include -#include #include +#include #include "rockchip_spdifrx.h" +#define QUIRK_ALWAYS_ON BIT(0) + struct rk_spdifrx_info { int sync; + int debounce_time_ms; + int liner_pcm; + int liner_pcm_last; unsigned int sample_rate_src; unsigned int sample_rate_cal; + unsigned int sample_rate_src_last; + unsigned int sample_rate_cal_last; + unsigned int sample_width; /* valid width */ + unsigned int sample_width_last; }; struct rk_spdifrx_dev { @@ -35,8 +46,23 @@ struct rk_spdifrx_dev { struct reset_control *reset; struct rk_spdifrx_info info; struct snd_soc_dai *dai; + struct timer_list debounce_timer; + struct timer_list non_liner_timer; + struct timer_list fifo_timer; + unsigned int mclk_rate; int irq; bool cdr_count_avg; + bool need_reset; +}; + +static const struct spdifrx_of_quirks { + char *quirk; + int id; +} of_quirks[] = { + { + .quirk = "rockchip,always-on", + .id = QUIRK_ALWAYS_ON, + }, }; static int rk_spdifrx_runtime_suspend(struct device *dev) @@ -78,17 +104,33 @@ static int rk_spdifrx_hw_params(struct snd_pcm_substream *substream, regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, SPDIFRX_INTEN_SYNCIE_MASK | SPDIFRX_INTEN_NSYNCIE_MASK | - SPDIFRX_INTEN_BTEIE_MASK, + SPDIFRX_INTEN_BTEIE_MASK | + SPDIFRX_INTEN_NPSPIE_MASK | + SPDIFRX_INTEN_BMDEIE_MASK | + SPDIFRX_INTEN_PEIE_MASK | + SPDIFRX_INTEN_CSCIE_MASK | + SPDIFRX_INTEN_NVLDIE_MASK, SPDIFRX_INTEN_SYNCIE_EN | SPDIFRX_INTEN_NSYNCIE_EN | - SPDIFRX_INTEN_BTEIE_EN); + SPDIFRX_INTEN_BTEIE_EN | + SPDIFRX_INTEN_NPSPIE_EN | + SPDIFRX_INTEN_BMDEIE_EN | + SPDIFRX_INTEN_PEIE_EN | + SPDIFRX_INTEN_CSCIE_EN | + SPDIFRX_INTEN_NVLDIE_EN); regmap_update_bits(spdifrx->regmap, SPDIFRX_DMACR, SPDIFRX_DMACR_RDL_MASK, SPDIFRX_DMACR_RDL(8)); regmap_update_bits(spdifrx->regmap, SPDIFRX_CDR, SPDIFRX_CDR_AVGSEL_MASK | SPDIFRX_CDR_BYPASS_MASK, - SPDIFRX_CDR_AVGSEL_MIN | SPDIFRX_CDR_BYPASS_DIS); + SPDIFRX_CDR_AVGSEL_MIN | SPDIFRX_CDR_BYPASS_EN); - if (params_rate(params) >= 32000) + spdifrx->need_reset = false; + spdifrx->info.sample_rate_cal_last = 0; + spdifrx->info.sample_rate_src_last = 0; + spdifrx->info.sample_width_last = 0; + spdifrx->info.liner_pcm_last = 1; + + if (params_rate(params) >= 44100) spdifrx->cdr_count_avg = true; else spdifrx->cdr_count_avg = false; @@ -147,6 +189,40 @@ static int rk_spdifrx_trigger(struct snd_pcm_substream *substream, return ret; } +static int rk_spdifrx_parse_quirks(struct rk_spdifrx_dev *spdifrx) +{ + int i = 0; + unsigned int quirks = 0; + + for (i = 0; i < ARRAY_SIZE(of_quirks); i++) + if (device_property_read_bool(spdifrx->dev, of_quirks[i].quirk)) + quirks |= of_quirks[i].id; + + if (quirks & QUIRK_ALWAYS_ON) { + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_SYNCIE_MASK | + SPDIFRX_INTEN_NSYNCIE_MASK | + SPDIFRX_INTEN_BTEIE_MASK | + SPDIFRX_INTEN_NPSPIE_MASK | + SPDIFRX_INTEN_BMDEIE_MASK | + SPDIFRX_INTEN_PEIE_MASK | + SPDIFRX_INTEN_CSCIE_MASK | + SPDIFRX_INTEN_NVLDIE_MASK, + SPDIFRX_INTEN_SYNCIE_EN | + SPDIFRX_INTEN_NSYNCIE_EN | + SPDIFRX_INTEN_BTEIE_EN | + SPDIFRX_INTEN_NPSPIE_EN | + SPDIFRX_INTEN_BMDEIE_EN | + SPDIFRX_INTEN_PEIE_EN | + SPDIFRX_INTEN_CSCIE_EN | + SPDIFRX_INTEN_NVLDIE_EN); + + pm_runtime_forbid(spdifrx->dev); + } + + return 0; +} + static int rk_spdifrx_sync_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -168,6 +244,46 @@ static int rk_spdifrx_sample_rate_get(struct snd_kcontrol *kcontrol, return 0; } +static int rk_spdifrx_debounce_time_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct rk_spdifrx_dev *spdifrx = snd_soc_dai_get_drvdata(dai); + + ucontrol->value.integer.value[0] = spdifrx->info.debounce_time_ms; + return 0; +} + +static int rk_spdifrx_debounce_time_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct rk_spdifrx_dev *spdifrx = snd_soc_dai_get_drvdata(dai); + + spdifrx->info.debounce_time_ms = ucontrol->value.integer.value[0]; + return 0; +} + +static int rk_spdifrx_sample_width_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct rk_spdifrx_dev *spdifrx = snd_soc_dai_get_drvdata(dai); + + ucontrol->value.integer.value[0] = spdifrx->info.sample_width; + return 0; +} + +static int rk_spdifrx_liner_pcm_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dai *dai = snd_kcontrol_chip(kcontrol); + struct rk_spdifrx_dev *spdifrx = snd_soc_dai_get_drvdata(dai); + + ucontrol->value.integer.value[0] = spdifrx->info.liner_pcm; + return 0; +} + static int rk_spdifrx_sync_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -190,6 +306,39 @@ static int rk_spdifrx_sample_rate_info(struct snd_kcontrol *kcontrol, return 0; } +static int rk_spdifrx_debounce_time_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1000; + + return 0; +} + +static int rk_spdifrx_sample_width_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 64; + + return 0; +} + +static int rk_spdifrx_liner_pcm_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + + return 0; +} + static struct snd_kcontrol_new rk_spdifrx_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -207,6 +356,29 @@ static struct snd_kcontrol_new rk_spdifrx_controls[] = { .info = rk_spdifrx_sample_rate_info, .get = rk_spdifrx_sample_rate_get, }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "RK SPDIFRX DEBOUNCE TIME", + .info = rk_spdifrx_debounce_time_info, + .get = rk_spdifrx_debounce_time_get, + .put = rk_spdifrx_debounce_time_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "RK SPDIFRX SAMPLE WIDTH", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = rk_spdifrx_sample_width_info, + .get = rk_spdifrx_sample_width_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "RK SPDIFRX LINER PCM", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = rk_spdifrx_liner_pcm_info, + .get = rk_spdifrx_liner_pcm_get, + }, }; static int rk_spdifrx_dai_probe(struct snd_soc_dai *dai) @@ -218,6 +390,8 @@ static int rk_spdifrx_dai_probe(struct snd_soc_dai *dai) snd_soc_add_dai_controls(dai, rk_spdifrx_controls, ARRAY_SIZE(rk_spdifrx_controls)); + rk_spdifrx_parse_quirks(spdifrx); + return 0; } @@ -261,6 +435,7 @@ static bool rk_spdifrx_wr_reg(struct device *dev, unsigned int reg) case SPDIFRX_INTCLR: case SPDIFRX_SMPDR: case SPDIFRX_CHNSR1: + case SPDIFRX_CHNSR2: case SPDIFRX_BURSTINFO: return true; default: @@ -283,6 +458,7 @@ static bool rk_spdifrx_rd_reg(struct device *dev, unsigned int reg) case SPDIFRX_INTCLR: case SPDIFRX_SMPDR: case SPDIFRX_CHNSR1: + case SPDIFRX_CHNSR2: case SPDIFRX_BURSTINFO: return true; default: @@ -301,6 +477,7 @@ static bool rk_spdifrx_volatile_reg(struct device *dev, unsigned int reg) case SPDIFRX_INTCLR: case SPDIFRX_SMPDR: case SPDIFRX_CHNSR1: + case SPDIFRX_CHNSR2: case SPDIFRX_BURSTINFO: return true; default: @@ -330,6 +507,30 @@ static const struct regmap_config rk_spdifrx_regmap_config = { .cache_type = REGCACHE_FLAT, }; +static unsigned int rk_spdifrx_get_sample_width(unsigned int flag) +{ + unsigned int width = 0; + + switch (flag) { + case IEC958_AES4_CON_WORDLEN_20_16: + width = 16; + break; + case IEC958_AES4_CON_WORDLEN_22_18: + width = 18; + break; + case IEC958_AES4_CON_WORDLEN_20_16 | IEC958_AES4_CON_MAX_WORDLEN_24: + width = 20; + break; + case IEC958_AES4_CON_WORDLEN_24_20 | IEC958_AES4_CON_MAX_WORDLEN_24: + width = 24; + break; + default: + return 0; + } + + return width; +} + static unsigned int rk_spdifrx_get_sample_rate(unsigned int flag) { unsigned int rate = 0; @@ -372,14 +573,61 @@ static unsigned int rk_spdifrx_get_sample_rate(unsigned int flag) return rate; } +static unsigned int rk_spdifrx_convert_sample_rate(unsigned int mclk, unsigned int count) +{ + unsigned int rate; + + rate = mclk / (count * 128); + + if (rate >= (8000 + 16000) / 2 && rate < (16000 + 22050) / 2) + return 16000; + + if (rate >= (16000 + 22050) / 2 && rate < (22050 + 24000) / 2) + return 22050; + + if (rate >= (22050 + 24000) / 2 && rate < (24000 + 32000) / 2) + return 24000; + + if (rate >= (24000 + 32000) / 2 && rate < (32000 + 44100) / 2) + return 32000; + + if (rate >= (32000 + 44100) / 2 && rate < (44100 + 48000) / 2) + return 44100; + + if (rate >= (44100 + 48000) / 2 && rate < (48000 + 88200) / 2) + return 48000; + + if (rate >= (48000 + 88200) / 2 && rate < (88200 + 96000) / 2) + return 88200; + + if (rate >= (88200 + 96000) / 2 && rate < (96000 + 192000) / 2) + return 96000; + + if (rate >= (96000 + 176400) / 2 && rate < (176400 + 192000) / 2) + return 176400; + + if (rate >= (176400 + 192000) / 2 && rate < (192000 + 384000) / 2) + return 192000; + + if (rate >= (192000 + 384000) / 2 && rate < (384000 + 768000) / 2) + return 384000; + + if (rate >= (384000 + 768000) / 2) + return 768000; + + return 0; +} + static irqreturn_t rk_spdifrx_isr(int irq, void *dev_id) { struct rk_spdifrx_dev *spdifrx = dev_id; struct snd_soc_dai *dai = spdifrx->dai; - struct snd_kcontrol *sync_kctl = snd_soc_card_get_kcontrol(dai->component->card, - "RK SPDIFRX SYNC STATUS"); struct snd_kcontrol *sample_kctl = snd_soc_card_get_kcontrol(dai->component->card, "RK SPDIFRX SAMPLE RATE"); + struct snd_kcontrol *width_kctl = snd_soc_card_get_kcontrol(dai->component->card, + "RK SPDIFRX SAMPLE WIDTH"); + struct snd_kcontrol *liner_pcm_kctl = snd_soc_card_get_kcontrol(dai->component->card, + "RK SPDIFRX LINER PCM"); u32 intsr; u32 val; u32 count; @@ -389,12 +637,60 @@ static irqreturn_t rk_spdifrx_isr(int irq, void *dev_id) regmap_read(spdifrx->regmap, SPDIFRX_INTSR, &intsr); + if (intsr & SPDIFRX_INTSR_NVLDISR_ACTIVE) { + dev_dbg(spdifrx->dev, "No Valid Error\n"); + regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_NVLDICLR); + rk_spdifrx_reset(spdifrx); + spdifrx->need_reset = true; + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_NVLDIE_MASK, SPDIFRX_INTEN_NVLDIE_DIS); + } + + if (intsr & SPDIFRX_INTSR_CSCISR_ACTIVE) { + dev_dbg(spdifrx->dev, "CSC Changed\n"); + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_BTEIE_MASK, SPDIFRX_INTEN_BTEIE_EN); + regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_CSCICLR); + } + + if (intsr & SPDIFRX_INTSR_PEISR_ACTIVE) { + dev_dbg(spdifrx->dev, "Parity Error\n"); + regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_PEICLR); + rk_spdifrx_reset(spdifrx); + spdifrx->need_reset = true; + } + + if (intsr & SPDIFRX_INTSR_NPSPISR_ACTIVE) { + spdifrx->info.liner_pcm = 0; + if (spdifrx->info.liner_pcm != spdifrx->info.liner_pcm_last) { + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &liner_pcm_kctl->id); + spdifrx->info.liner_pcm_last = spdifrx->info.liner_pcm; + dev_dbg(spdifrx->dev, "non liner data\n"); + } + mod_timer(&spdifrx->non_liner_timer, jiffies + msecs_to_jiffies(100)); + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_NVLDIE_MASK, SPDIFRX_INTEN_NVLDIE_DIS); + regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_NPSPICLR); + } + + if (intsr & SPDIFRX_INTSR_BMDEISR_ACTIVE) { + dev_dbg(spdifrx->dev, "BMD Error\n"); + regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_BMDEICLR); + rk_spdifrx_reset(spdifrx); + spdifrx->need_reset = true; + } + if (intsr & SPDIFRX_INTSR_NSYNCISR_ACTIVE) { spdifrx->info.sync = 0; - snd_ctl_notify(dai->component->card->snd_card, - SNDRV_CTL_EVENT_MASK_VALUE, &sync_kctl->id); + spdifrx->need_reset = true; + mod_timer(&spdifrx->debounce_timer, jiffies + + msecs_to_jiffies(spdifrx->info.debounce_time_ms)); dev_dbg(spdifrx->dev, "NSYNC\n"); + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, SPDIFRX_INTEN_NSYNCIE_MASK, + SPDIFRX_INTEN_NSYNCIE_DIS); regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_NSYNCICLR); + regmap_write(spdifrx->regmap, SPDIFRX_CLR, 0x1); } if (intsr & SPDIFRX_INTSR_BTEISR_ACTIVE) { @@ -404,28 +700,58 @@ static irqreturn_t rk_spdifrx_isr(int irq, void *dev_id) regmap_read(spdifrx->regmap, SPDIFRX_CDRST, &val); if (spdifrx->cdr_count_avg) - count = ((val & SPDIFRX_CDRST_MINCNT_MASK) + - ((val & SPDIFRX_CDRST_MAXCNT_MASK) >> 8)) / 4; + count = ((val & SPDIFRX_CDRST_MINCNT_MASK) + 1 + + ((val & SPDIFRX_CDRST_MAXCNT_MASK) >> 8) + 1) / 4; else - count = val & SPDIFRX_CDRST_MINCNT_MASK; - spdifrx->info.sample_rate_cal = clk_get_rate(spdifrx->mclk) / (count * 128); - snd_ctl_notify(dai->component->card->snd_card, - SNDRV_CTL_EVENT_MASK_VALUE, &sample_kctl->id); + count = (val & SPDIFRX_CDRST_MINCNT_MASK) + 1; + + if (count > 0) + spdifrx->info.sample_rate_cal = + rk_spdifrx_convert_sample_rate(spdifrx->mclk_rate, count); + else + spdifrx->info.sample_rate_cal = 0; + + regmap_read(spdifrx->regmap, SPDIFRX_CHNSR2, &val); + spdifrx->info.sample_width = + rk_spdifrx_get_sample_width(val & SPDIFRX_CHNSR2_SAMPLE_WIDTH_MASK); + + if (spdifrx->info.sample_rate_src != spdifrx->info.sample_rate_src_last || + spdifrx->info.sample_rate_cal != spdifrx->info.sample_rate_cal_last) { + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &sample_kctl->id); + spdifrx->info.sample_rate_src_last = spdifrx->info.sample_rate_src; + spdifrx->info.sample_rate_cal_last = spdifrx->info.sample_rate_cal; + dev_dbg(spdifrx->dev, "src sample rate: %u Hz\n", + spdifrx->info.sample_rate_src); + dev_dbg(spdifrx->dev, "cal sample rate: %u Hz\n", + spdifrx->info.sample_rate_cal); + } + + if (spdifrx->info.sample_width != spdifrx->info.sample_width_last) { + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &width_kctl->id); + spdifrx->info.sample_width_last = spdifrx->info.sample_width; + dev_dbg(spdifrx->dev, "sample width: %u bit\n", spdifrx->info.sample_width); + } - dev_dbg(spdifrx->dev, "src sample rate: %u Hz\n", spdifrx->info.sample_rate_src); - dev_dbg(spdifrx->dev, "cal sample rate: %u Hz\n", spdifrx->info.sample_rate_cal); dev_dbg(spdifrx->dev, "BTEIE\n"); regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_BTECLR); - regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, SPDIFRX_INTEN_BTEIE_MASK, - SPDIFRX_INTEN_BTEIE_DIS); + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_BTEIE_MASK, SPDIFRX_INTEN_BTEIE_DIS); } if (intsr & SPDIFRX_INTSR_SYNCISR_ACTIVE) { spdifrx->info.sync = 1; - snd_ctl_notify(dai->component->card->snd_card, - SNDRV_CTL_EVENT_MASK_VALUE, &sync_kctl->id); + mod_timer(&spdifrx->debounce_timer, jiffies + + msecs_to_jiffies(spdifrx->info.debounce_time_ms)); + regmap_read(spdifrx->regmap, SPDIFRX_CDRST, &val); + dev_dbg(spdifrx->dev, "MINCNT = %lu, MAXCNT = %lu\n", + val & SPDIFRX_CDRST_MINCNT_MASK, (val & SPDIFRX_CDRST_MAXCNT_MASK) >> 8); dev_dbg(spdifrx->dev, "SYNC\n"); + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_BTEIE_MASK | SPDIFRX_INTEN_NSYNCIE_MASK, + SPDIFRX_INTEN_BTEIE_EN | SPDIFRX_INTEN_NSYNCIE_EN); regmap_write(spdifrx->regmap, SPDIFRX_INTCLR, SPDIFRX_INTCLR_SYNCICLR); } @@ -434,6 +760,119 @@ static irqreturn_t rk_spdifrx_isr(int irq, void *dev_id) return IRQ_HANDLED; } +/* + * Check if data has been received into the rxfifo. + * + * Within the timeout_us interval, poll the SPDIFRX_FIFOCTRL + * register via regmap_read_poll_timeout_atomic to detect new + * data entries in the fifo + * + * The timeout_us parameter corresponds to the time required + * for a 32-bit data entry to be written into the fifo, which + * is inversely proportional to the sample rate, with a maximum + * value of 32μs (at 16kHz sample rate). + * + * If the actual polling duration exceeds the timeout_us by a + * predefined threshold, the current detection result is invalidated, + * and the system proceeds to the next scheduled timer interval. + */ +static void rk_spdifrx_fifo_timer_isr(struct timer_list *timer) +{ + struct rk_spdifrx_dev *spdifrx = from_timer(spdifrx, timer, fifo_timer); + unsigned int val, timeout_us; + unsigned int fifo_cnt; + ktime_t start, end; + int ret; + + if (spdifrx->info.sync == 0 || spdifrx->need_reset || spdifrx->info.sample_rate_src == 0) + return; + + timeout_us = DIV_ROUND_UP(500000, spdifrx->info.sample_rate_src); + + start = ktime_get(); + regmap_read(spdifrx->regmap, SPDIFRX_FIFOCTRL, &val); + fifo_cnt = (val & SPDIFRX_FIFOCTRL_RFL_MASK) >> 8; + + if (fifo_cnt < 8) { + ret = regmap_read_poll_timeout_atomic(spdifrx->regmap, SPDIFRX_FIFOCTRL, val, + ((val & SPDIFRX_FIFOCTRL_RFL_MASK) >> 8) != + fifo_cnt, 1, timeout_us); + end = ktime_get(); + if (ret == -ETIMEDOUT && ktime_us_delta(end, start) < 8 * timeout_us) { + dev_info(spdifrx->dev, "no data to fifo, reset\n"); + rk_spdifrx_reset(spdifrx); + spdifrx->need_reset = true; + return; + } + } + mod_timer(&spdifrx->fifo_timer, jiffies + msecs_to_jiffies(100)); +} + +static void rk_spdifrx_non_liner_timer_isr(struct timer_list *timer) +{ + struct rk_spdifrx_dev *spdifrx = from_timer(spdifrx, timer, non_liner_timer); + struct snd_soc_dai *dai = spdifrx->dai; + struct snd_kcontrol *liner_pcm_kctl = snd_soc_card_get_kcontrol(dai->component->card, + "RK SPDIFRX LINER PCM"); + + spdifrx->info.liner_pcm = 1; + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &liner_pcm_kctl->id); + spdifrx->info.liner_pcm_last = spdifrx->info.liner_pcm; + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_NVLDIE_MASK, SPDIFRX_INTEN_NVLDIE_EN); + dev_dbg(spdifrx->dev, "liner data\n"); +} + +static void rk_spdifrx_debounce_timer_isr(struct timer_list *timer) +{ + struct rk_spdifrx_dev *spdifrx = from_timer(spdifrx, timer, debounce_timer); + struct snd_soc_dai *dai = spdifrx->dai; + struct snd_kcontrol *sync_kctl = snd_soc_card_get_kcontrol(dai->component->card, + "RK SPDIFRX SYNC STATUS"); + struct snd_kcontrol *sample_kctl = snd_soc_card_get_kcontrol(dai->component->card, + "RK SPDIFRX SAMPLE RATE"); + u32 val; + u32 count; + + if (spdifrx->info.sync == 1) { + if (spdifrx->need_reset) { + rk_spdifrx_reset(spdifrx); + spdifrx->need_reset = false; + } else { + regmap_read(spdifrx->regmap, SPDIFRX_CDRST, &val); + if (spdifrx->cdr_count_avg) + count = ((val & SPDIFRX_CDRST_MINCNT_MASK) + 1 + + ((val & SPDIFRX_CDRST_MAXCNT_MASK) >> 8) + 1) / 4; + else + count = (val & SPDIFRX_CDRST_MINCNT_MASK) + 1; + + if (count > 0) + spdifrx->info.sample_rate_cal = + rk_spdifrx_convert_sample_rate(spdifrx->mclk_rate, count); + else + spdifrx->info.sample_rate_cal = 0; + + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &sample_kctl->id); + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &sync_kctl->id); + spdifrx->info.sample_rate_cal_last = spdifrx->info.sample_rate_cal; + mod_timer(&spdifrx->fifo_timer, jiffies + msecs_to_jiffies(1000)); + if (spdifrx->info.liner_pcm == 1) + regmap_update_bits(spdifrx->regmap, SPDIFRX_INTEN, + SPDIFRX_INTEN_NVLDIE_MASK, + SPDIFRX_INTEN_NVLDIE_EN); + dev_dbg(spdifrx->dev, "notify sync and sample_rate_cal = %u hz\n", + spdifrx->info.sample_rate_cal); + } + } else if (spdifrx->info.sync == 0) { + snd_ctl_notify(dai->component->card->snd_card, + SNDRV_CTL_EVENT_MASK_VALUE, &sync_kctl->id); + dev_dbg(spdifrx->dev, "notify usync\n"); + } +} + static int rk_spdifrx_probe(struct platform_device *pdev) { struct rk_spdifrx_dev *spdifrx; @@ -460,10 +899,19 @@ static int rk_spdifrx_probe(struct platform_device *pdev) if (IS_ERR(spdifrx->mclk)) return PTR_ERR(spdifrx->mclk); + spdifrx->mclk_rate = clk_get_rate(spdifrx->mclk); + spdifrx->irq = platform_get_irq(pdev, 0); if (spdifrx->irq < 0) return spdifrx->irq; + spdifrx->info.debounce_time_ms = 100; + spdifrx->info.liner_pcm = 1; + spdifrx->info.liner_pcm_last = 1; + timer_setup(&spdifrx->debounce_timer, rk_spdifrx_debounce_timer_isr, 0); + timer_setup(&spdifrx->non_liner_timer, rk_spdifrx_non_liner_timer_isr, 0); + timer_setup(&spdifrx->fifo_timer, rk_spdifrx_fifo_timer_isr, 0); + ret = devm_request_threaded_irq(&pdev->dev, spdifrx->irq, NULL, rk_spdifrx_isr, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, @@ -483,7 +931,7 @@ static int rk_spdifrx_probe(struct platform_device *pdev) spdifrx->capture_dma_data.addr = res->start + SPDIFRX_SMPDR; spdifrx->capture_dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; - spdifrx->capture_dma_data.maxburst = 4; + spdifrx->capture_dma_data.maxburst = 8; spdifrx->dev = &pdev->dev; dev_set_drvdata(&pdev->dev, spdifrx); @@ -522,6 +970,12 @@ err_pm_runtime: static int rk_spdifrx_remove(struct platform_device *pdev) { + struct rk_spdifrx_dev *spdifrx = dev_get_drvdata(&pdev->dev); + + del_timer_sync(&spdifrx->debounce_timer); + del_timer_sync(&spdifrx->non_liner_timer); + del_timer_sync(&spdifrx->fifo_timer); + pm_runtime_disable(&pdev->dev); if (!pm_runtime_status_suspended(&pdev->dev)) rk_spdifrx_runtime_suspend(&pdev->dev); diff --git a/sound/soc/rockchip/rockchip_spdifrx.h b/sound/soc/rockchip/rockchip_spdifrx.h index ee9f4c78f040..b72a68f95385 100644 --- a/sound/soc/rockchip/rockchip_spdifrx.h +++ b/sound/soc/rockchip/rockchip_spdifrx.h @@ -58,6 +58,21 @@ #define SPDIFRX_INTEN_NSYNCIE_MASK BIT(7) #define SPDIFRX_INTEN_NSYNCIE_EN BIT(7) #define SPDIFRX_INTEN_NSYNCIE_DIS (0 << 7) +#define SPDIFRX_INTEN_BMDEIE_MASK BIT(6) +#define SPDIFRX_INTEN_BMDEIE_EN BIT(6) +#define SPDIFRX_INTEN_BMDEIE_DIS (0 << 6) +#define SPDIFRX_INTEN_NPSPIE_MASK BIT(3) +#define SPDIFRX_INTEN_NPSPIE_EN BIT(3) +#define SPDIFRX_INTEN_NPSPIE_DIS (0 << 3) +#define SPDIFRX_INTEN_NVLDIE_MASK BIT(2) +#define SPDIFRX_INTEN_NVLDIE_EN BIT(2) +#define SPDIFRX_INTEN_NVLDIE_DIS (0 << 2) +#define SPDIFRX_INTEN_CSCIE_MASK BIT(1) +#define SPDIFRX_INTEN_CSCIE_EN BIT(1) +#define SPDIFRX_INTEN_CSCIE_DIS (0 << 1) +#define SPDIFRX_INTEN_PEIE_MASK BIT(0) +#define SPDIFRX_INTEN_PEIE_EN BIT(0) +#define SPDIFRX_INTEN_PEIE_DIS (0 << 0) /* INTMASK */ #define SPDIFRX_INTMASK_UBCIMSK BIT(10) @@ -68,12 +83,27 @@ #define SPDIFRX_INTMASK_BTEIUMSK (0 << 8) #define SPDIFRX_INTMASK_NSYNCIMSK BIT(7) #define SPDIFRX_INTMASK_NSYNCIUMSK (0 << 7) +#define SPDIFRX_INTMASK_BMDEIMSK BIT(6) +#define SPDIFRX_INTMASK_BMDEIUMSK (0 << 6) +#define SPDIFRX_INTMASK_NPSPIMSK BIT(3) +#define SPDIFRX_INTMASK_NPSPIUMSK (0 << 3) +#define SPDIFRX_INTMASK_NVLDIMSK BIT(2) +#define SPDIFRX_INTMASK_NVLDIUMSK (0 << 2) +#define SPDIFRX_INTMASK_CSCIMSK BIT(1) +#define SPDIFRX_INTMASK_CSCIUMSK (0 << 1) +#define SPDIFRX_INTMASK_PEIMSK BIT(0) +#define SPDIFRX_INTMASK_PEIUMSK (0 << 0) /* INTSR */ #define SPDIFRX_INTSR_UBCISR_ACTIVE BIT(10) #define SPDIFRX_INTSR_SYNCISR_ACTIVE BIT(9) #define SPDIFRX_INTSR_BTEISR_ACTIVE BIT(8) #define SPDIFRX_INTSR_NSYNCISR_ACTIVE BIT(7) +#define SPDIFRX_INTSR_BMDEISR_ACTIVE BIT(6) +#define SPDIFRX_INTSR_NPSPISR_ACTIVE BIT(3) +#define SPDIFRX_INTSR_NVLDISR_ACTIVE BIT(2) +#define SPDIFRX_INTSR_CSCISR_ACTIVE BIT(1) +#define SPDIFRX_INTSR_PEISR_ACTIVE BIT(0) /* INTCLR */ #define SPDIFRX_INTCLR_UBCICLR_MASK BIT(10) @@ -84,9 +114,20 @@ #define SPDIFRX_INTCLR_BTECLR BIT(8) #define SPDIFRX_INTCLR_NSYNCICLR_MASK BIT(7) #define SPDIFRX_INTCLR_NSYNCICLR BIT(7) +#define SPDIFRX_INTCLR_BMDEICLR_MASK BIT(6) +#define SPDIFRX_INTCLR_BMDEICLR BIT(6) +#define SPDIFRX_INTCLR_NPSPICLR_MASK BIT(3) +#define SPDIFRX_INTCLR_NPSPICLR BIT(3) +#define SPDIFRX_INTCLR_NVLDICLR_MASK BIT(2) +#define SPDIFRX_INTCLR_NVLDICLR BIT(2) +#define SPDIFRX_INTCLR_CSCICLR_MASK BIT(1) +#define SPDIFRX_INTCLR_CSCICLR BIT(1) +#define SPDIFRX_INTCLR_PEICLR_MASK BIT(0) +#define SPDIFRX_INTCLR_PEICLR BIT(0) /* SPDIFRX_CHNSRN */ -#define SPDIFRX_CHNSR1_SAMPLE_RATE_MASK GENMASK(11, 8) +#define SPDIFRX_CHNSR1_SAMPLE_RATE_MASK GENMASK(11, 8) +#define SPDIFRX_CHNSR2_SAMPLE_WIDTH_MASK GENMASK(3, 0) /* BURSTINFO */ #define SPDIFRX_BURSTINFO_PD_MASK GENMASK(31, 16) @@ -111,6 +152,7 @@ #define SPDIFRX_SMPDR (0x002C) #define SPDIFRX_USRDRN (0x0030) #define SPDIFRX_CHNSR1 (0x0064) +#define SPDIFRX_CHNSR2 (0x0068) #define SPDIFRX_BURSTINFO (0x0100) #endif /* _ROCKCHIP_SPDIFRX_H */