mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 10:31:46 +09:00
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:
committed by
Tao Huang
parent
bb3fd4709b
commit
eae70e5ad3
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user