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 <shengquan.zhong@rock-chips.com>
This commit is contained in:
Zhong Shengquan
2025-02-18 16:25:26 +08:00
committed by Tao Huang
parent bb3fd4709b
commit eae70e5ad3
2 changed files with 523 additions and 27 deletions

View File

@@ -6,24 +6,35 @@
*
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/of_gpio.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/pm_runtime.h>
#include <linux/regmap.h>
#include <linux/reset.h>
#include <linux/timer.h>
#include <sound/asoundef.h>
#include <sound/pcm_params.h>
#include <sound/dmaengine_pcm.h>
#include <sound/pcm_params.h>
#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);

View File

@@ -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 */