#define DRV_NAME "EXTN"
+#define MAX_INT 0x7ffffff
+
+struct extn_chipinfo {
+ /* try to check papb before fetch pcpd
+ * no nonpcm2pcm irq for tl1
+ */
+ bool no_nonpcm2pcm_clr;
+};
+
struct extn {
struct aml_audio_controller *actrl;
struct device *dev;
int arc_src;
int arc_en;
+ /* check whether irq generating
+ * if not, reset
+ * 'cuase no irq from nonpcm2pcm, do it by sw.
+ */
+ unsigned int frhdmirx_cnt; /* irq counter */
+ unsigned int frhdmirx_last_cnt;
+ unsigned int frhdmirx_same_cnt;
+ bool nonpcm_flag;
+
+ struct extn_chipinfo *chipinfo;
};
-#define PREALLOC_BUFFER (128 * 1024)
+#define PREALLOC_BUFFER (256 * 1024)
#define PREALLOC_BUFFER_MAX (256 * 1024)
#define EXTN_RATES (SNDRV_PCM_RATE_8000_192000)
.channels_max = 32,
};
+static void frhdmirx_nonpcm2pcm_clr_reset(struct extn *p_extn)
+{
+ p_extn->frhdmirx_cnt = 0;
+ p_extn->frhdmirx_last_cnt = 0;
+ p_extn->frhdmirx_same_cnt = 0;
+}
+
static irqreturn_t extn_ddr_isr(int irq, void *devid)
{
struct snd_pcm_substream *substream =
(struct snd_pcm_substream *)devid;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct device *dev = rtd->platform->dev;
+ struct extn *p_extn = (struct extn *)dev_get_drvdata(dev);
if (!snd_pcm_running(substream))
return IRQ_HANDLED;
snd_pcm_period_elapsed(substream);
+ /* check pcm or nonpcm */
+ if (p_extn &&
+ p_extn->chipinfo &&
+ p_extn->chipinfo->no_nonpcm2pcm_clr) {
+ if (p_extn->frhdmirx_last_cnt == p_extn->frhdmirx_cnt) {
+
+ p_extn->frhdmirx_same_cnt++;
+
+ if (p_extn->frhdmirx_same_cnt > 5)
+ frhdmirx_nonpcm2pcm_clr_reset(p_extn);
+
+ if (p_extn->frhdmirx_cnt == 0)
+ p_extn->nonpcm_flag = false;
+ } else {
+ p_extn->frhdmirx_last_cnt = p_extn->frhdmirx_cnt;
+ p_extn->frhdmirx_same_cnt = 0;
+ p_extn->nonpcm_flag = true;
+ frhdmirx_clr_PAO_irq_bits();
+ }
+ }
+
return IRQ_HANDLED;
}
static irqreturn_t frhdmirx_isr(int irq, void *devid)
{
+ struct extn *p_extn = (struct extn *)devid;
+
+ p_extn->frhdmirx_cnt++;
+ if (p_extn->frhdmirx_cnt > MAX_INT - 2)
+ frhdmirx_nonpcm2pcm_clr_reset(p_extn);
+
return IRQ_HANDLED;
}
else {
aml_audio_unregister_toddr(p_extn->dev, substream);
- if (toddr_src_get() == FRHDMIRX)
+ if (toddr_src_get() == FRHDMIRX) {
+ frhdmirx_nonpcm2pcm_clr_reset(p_extn);
+ if (p_extn->hdmirx_mode == 1)
+ frhdmirx_clr_PAO_irq_bits();
free_irq(p_extn->irq_frhdmirx, p_extn);
+ }
}
runtime->private_data = NULL;
{3, 0xb, "DTS-I"},
{3, 0x0c, "DTS-II"},
{3, 0x0d, "DTS-III"},
- {3, 0x11, "DTS-IV"},
+ {4, 0x11, "DTS-IV"},
{4, 0, "DTS-HD"},
{5, 0x16, "TRUEHD"},
{6, 0x103, "PAUSE"},
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_audio_type_texts),
spdif_audio_type_texts);
-static int hdmiin_check_audio_type(void)
+static int hdmiin_check_audio_type(struct extn *p_extn)
{
int total_num = sizeof(type_texts)/sizeof(struct sppdif_audio_info);
int pc = frhdmirx_get_chan_status_pc();
int audio_type = 0;
int i;
+ if (!p_extn->nonpcm_flag)
+ return audio_type;
+
for (i = 0; i < total_num; i++) {
if (pc == type_texts[i].pc) {
audio_type = type_texts[i].aud_type;
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct extn *p_extn = dev_get_drvdata(component->dev);
+
ucontrol->value.enumerated.item[0] =
- hdmiin_check_audio_type();
+ hdmiin_check_audio_type(p_extn);
+
return 0;
}
#endif
0,
aml_get_atmos_audio_edid,
aml_set_atmos_audio_edid),
+
SOC_ENUM_EXT("HDMIIN Audio Type",
hdmirx_audio_type_enum,
hdmirx_audio_type_get_enum,
.name = DRV_NAME,
};
+struct extn_chipinfo tl1_extn_chipinfo = {
+ .no_nonpcm2pcm_clr = true,
+};
+
static const struct of_device_id extn_device_id[] = {
{
.compatible = "amlogic, snd-extn",
+ .data = &tl1_extn_chipinfo,
+ },
+ {
+ .compatible = "amlogic, tl1-snd-extn",
+ .data = &tl1_extn_chipinfo,
},
{},
};
struct device *dev = &pdev->dev;
struct aml_audio_controller *actrl = NULL;
struct extn *p_extn = NULL;
+ struct extn_chipinfo *p_chipinfo;
int ret = 0;
-
p_extn = devm_kzalloc(dev, sizeof(struct extn), GFP_KERNEL);
if (!p_extn)
return -ENOMEM;
p_extn->dev = dev;
dev_set_drvdata(dev, p_extn);
+ /* match data */
+ p_chipinfo = (struct extn_chipinfo *)
+ of_device_get_match_data(dev);
+ if (!p_chipinfo)
+ dev_warn_once(dev, "check whether to update chipinfo\n");
+ else
+ p_extn->chipinfo = p_chipinfo;
+
/* get audio controller */
node_prt = of_get_parent(node);
if (node_prt == NULL)
/* Default ARC SRC */
p_extn->arc_src = 1;
- /* Default: SPDIF in mode */
- p_extn->hdmirx_mode = 0;
+ /* Default: PAO mode */
+ p_extn->hdmirx_mode = 1;
ret = snd_soc_register_component(&pdev->dev,
&extn_component,
*
*/
#include <linux/types.h>
+#include <linux/kernel.h>
#include "frhdmirx_hw.h"
#include "regs.h"
(bool)src << 23);
}
-void frhdmirx_enable_irq_bits(int channels, int src)
+static void frhdmirx_enable_irq_bits(int channels, int src)
{
int lane, int_bits = 0, i;
/* interrupt bits */
if (src) { /* PAO mode */
- int_bits = (0x1 << 24 | /* PAO data: find papb */
- 0x1 << 16 /* PAO data: find pcpd changed */
+ int_bits = (
+ 0x1 << INT_PAO_PAPB_MASK | /* find papb */
+ 0x1 << INT_PAO_PCPD_MASK /* find pcpd changed */
);
- } else { /* SPDIF Lane*/
+ } else { /* SPDIF Lane */
int lane_irq_bits = (0x1 << 7 | /* lane: find papb */
0x1 << 6 | /* lane: find papb */
0x1 << 5 | /* lane: find nonpcm to pcm */
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL2, int_bits);
}
+void frhdmirx_clr_irq_bits(int channels, int src)
+{
+ int lane, int_clr_mask = 0, i;
+
+ if (channels % 2)
+ lane = channels / 2 + 1;
+ else
+ lane = channels / 2;
+
+ /* interrupt bits */
+ if (src) { /* PAO mode */
+ int_clr_mask = (
+ 0x1 << INT_PAO_PAPB_MASK | /* find papb */
+ 0x1 << INT_PAO_PCPD_MASK /* find pcpd changed */
+ );
+ } else { /* SPDIF Lane */
+ int lane_irq_bits = (0x1 << 7 | /* lane: find papb */
+ 0x1 << 6 | /* lane: find valid changed; */
+ 0x1 << 5 | /* lane: find nonpcm to pcm */
+ 0x1 << 4 | /* lane: find pcpd changed */
+ 0x1 << 3 | /* lane: find ch status changed */
+ 0x1 << 1 /* lane: find parity error */
+ );
+
+ for (i = 0; i < lane; i++)
+ int_clr_mask |= (lane_irq_bits << i);
+ }
+ audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, ~int_clr_mask);
+ audiobus_write(EE_AUDIO_FRHDMIRX_CTRL3, int_clr_mask);
+ audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, ~int_clr_mask);
+ audiobus_write(EE_AUDIO_FRHDMIRX_CTRL4, int_clr_mask);
+}
+
void frhdmirx_ctrl(int channels, int src)
{
int lane, lane_mask = 0, i;
/* PAO mode */
if (src) {
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL0,
- 0x1 << 23 | /* slect pao mode */
0x1 << 22 | /* capture input by fall edge*/
- 0x1 << 7 | /* start sending ch num info out */
0x1 << 8 | /* start detect PAPB */
- 0x1 << 6 /* chan status sel: pao pc/pd value */);
- return;
- }
-
- if (channels % 2)
- lane = channels / 2 + 1;
- else
- lane = channels / 2;
-
- for (i = 0; i < lane; i++)
- lane_mask |= (1 << i);
+ 0x4 << 4 /* chan status sel: pao pc/pd value */
+ );
+ } else {
+ if (channels % 2)
+ lane = channels / 2 + 1;
+ else
+ lane = channels / 2;
- audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
- 0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11,
- 0x1 << 30 | /* chnum_sel */
- lane_mask << 24 | /* chnum_sel */
- 0x1 << 22 | /* clk_inv */
- 0x0 << 11 /* req_sel, Sync 4 spdifin by which */
- );
+ for (i = 0; i < lane; i++)
+ lane_mask |= (1 << i);
+ audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL0,
+ 0x1 << 30 | 0xf << 24 | 0x1 << 22 | 0x3 << 11,
+ 0x1 << 30 | /* chnum_sel */
+ lane_mask << 24 | /* chnum_sel */
+ 0x1 << 22 | /* clk_inv */
+ 0x0 << 11 /* req_sel, Sync 4 spdifin by which */
+ );
+ }
/* nonpcm2pcm_th */
audiobus_write(EE_AUDIO_FRHDMIRX_CTRL1, 0xff << 20);
frhdmirx_enable_irq_bits(channels, src);
}
+void frhdmirx_clr_PAO_irq_bits(void)
+{
+ audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4,
+ 0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK,
+ 0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK);
+
+ audiobus_update_bits(EE_AUDIO_FRHDMIRX_CTRL4,
+ 0x1 << INT_PAO_PAPB_MASK | 0x1 << INT_PAO_PCPD_MASK,
+ 0x0 << INT_PAO_PAPB_MASK | 0x0 << INT_PAO_PCPD_MASK);
+}
+
+unsigned int frhdmirx_get_ch_status0to31(void)
+{
+ return (unsigned int)audiobus_read(EE_AUDIO_FRHDMIRX_STAT0);
+}
+
unsigned int frhdmirx_get_chan_status_pc(void)
{
unsigned int val;
val = audiobus_read(EE_AUDIO_FRHDMIRX_STAT1);
return (val >> 16) & 0xff;
}
-
-
-