1093 lines
32 KiB
C
1093 lines
32 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
|
* Author: Jason Zhang <jason.zhang@rock-chips.com>
|
|
*/
|
|
|
|
#include <linux/notifier.h>
|
|
#include <sound/asoundef.h>
|
|
|
|
#include "it6621.h"
|
|
#include "it6621-clk.h"
|
|
#include "it6621-earc.h"
|
|
#include "it6621-reg-bank0.h"
|
|
#include "it6621-reg-bank1.h"
|
|
#include "it6621-reg-cec.h"
|
|
#include "it6621-uapi.h"
|
|
|
|
int it6621_set_channel_status(struct it6621_priv *priv)
|
|
{
|
|
unsigned int layout = 0;
|
|
unsigned int ca = 0;
|
|
unsigned int fmt = 0;
|
|
unsigned int wl = 0;
|
|
unsigned int fs = 0;
|
|
|
|
/* NOTE: Add for Category code */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST1, 0xff,
|
|
IEC958_AES1_CON_PCM_CODER);
|
|
|
|
/* Refer to HDMI2.1 spec table 9-23 and ICE60958-3 p9 */
|
|
if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_ch == 2) && (priv->audio_enc == 0) &&
|
|
(priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_DIS) &&
|
|
(priv->i2s_nlpcm_enabled == IT6621_TX_NLPCM_I2S_DIS))
|
|
fmt = HDMI_AUDIO_FMT_UN_2CH_LPCM;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_ch == 2) && (priv->audio_enc == 0) &&
|
|
(priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN))
|
|
fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_ch > 2) && (priv->audio_enc == 0))
|
|
fmt = HDMI_AUDIO_FMT_UN_MCH_LPCM;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) &&
|
|
(priv->audio_enc == 0))
|
|
fmt = HDMI_AUDIO_FMT_UN_XCH_DSD;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) &&
|
|
(priv->audio_enc == 0))
|
|
fmt = HDMI_AUDIO_FMT_UN_2CH_NLPCM;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) &&
|
|
(priv->audio_enc == 1))
|
|
fmt = HDMI_AUDIO_FMT_EN_2CH_NLPCM;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_enc == 1))
|
|
fmt = HDMI_AUDIO_FMT_EN_MCH_NLPCM;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) &&
|
|
(priv->audio_enc == 1))
|
|
fmt = HDMI_AUDIO_FMT_EN_XCH_DSD;
|
|
else
|
|
dev_err(priv->dev, "invalid audio format\n");
|
|
|
|
/*
|
|
* NOTE: Software for which copyright is asserted, Channel status mode
|
|
* is set to mode 0, and audio format is set with fmt.
|
|
*/
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST0,
|
|
((fmt & 0x1c) << 1) | (fmt & 0x03));
|
|
|
|
/* Refer to IEC60958-3 p12 */
|
|
if (priv->audio_src == IT6621_AUD_SRC_DSD)
|
|
wl = IEC958_AES4_CON_WORDLEN_NOTID;
|
|
else if (priv->audio_type == IT6621_AUD_TYPE_NLPCM)
|
|
wl = IEC958_AES4_CON_WORDLEN_20_16;
|
|
else
|
|
wl = priv->i2s_wl;
|
|
|
|
/* NOTE: Set sample word length */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_CH_ST4, 0x0f, wl);
|
|
|
|
/* Refer to HDMI2.1 spec table 9-25 and IEC60958-3 p12 */
|
|
if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_ch <= 2))
|
|
layout = HDMI_AUDIO_LAYOUT_LPCM_2CH;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_ch <= 8))
|
|
layout = HDMI_AUDIO_LAYOUT_LPCM_8CH;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_LPCM) &&
|
|
(priv->audio_ch <= 16))
|
|
layout = HDMI_AUDIO_LAYOUT_LPCM_16CH;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) &&
|
|
(priv->audio_ch <= 2))
|
|
layout = HDMI_AUDIO_LAYOUT_NLPCM_2CH;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) &&
|
|
(priv->audio_ch <= 8))
|
|
layout = HDMI_AUDIO_LAYOUT_NLPCM_8CH;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) &&
|
|
(priv->audio_ch <= 6))
|
|
layout = HDMI_AUDIO_LAYOUT_DSD_6CH;
|
|
else if ((priv->audio_type == IT6621_AUD_TYPE_DSD) &&
|
|
(priv->audio_ch <= 12))
|
|
layout = HDMI_AUDIO_LAYOUT_DSD_12CH;
|
|
else
|
|
dev_err(priv->dev, "invalid layout\n");
|
|
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST5, layout << 4);
|
|
|
|
/* Refer to HDMI2.0 spec, IEC60958-3 p11 and p12 */
|
|
if ((layout == HDMI_AUDIO_LAYOUT_LPCM_2CH) ||
|
|
(layout == HDMI_AUDIO_LAYOUT_NLPCM_2CH)) {
|
|
fs = priv->audio_fs;
|
|
} else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_8CH) ||
|
|
(layout == HDMI_AUDIO_LAYOUT_NLPCM_8CH)) {
|
|
if (priv->audio_fs == IEC958_AES3_CON_FS_32000)
|
|
fs = IT6621_AES3_CON_FS_128000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_44100)
|
|
fs = IEC958_AES3_CON_FS_176400;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_48000)
|
|
fs = IEC958_AES3_CON_FS_192000;
|
|
else if (priv->audio_fs == IT6621_AES3_CON_FS_64000)
|
|
fs = IT6621_AES3_CON_FS_256000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_88200)
|
|
fs = IT6621_AES3_CON_FS_352000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_96000)
|
|
fs = IT6621_AES3_CON_FS_384000;
|
|
else if (priv->audio_fs == IT6621_AES3_CON_FS_128000)
|
|
fs = IT6621_AES3_CON_FS_512000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_176400)
|
|
fs = IT6621_AES3_CON_FS_705000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_192000)
|
|
fs = IEC958_AES3_CON_FS_768000;
|
|
else
|
|
dev_err(priv->dev, "invalid fs and channel\n");
|
|
} else if ((layout == HDMI_AUDIO_LAYOUT_LPCM_16CH) ||
|
|
(layout == HDMI_AUDIO_LAYOUT_DSD_6CH)) {
|
|
if (priv->audio_fs == IEC958_AES3_CON_FS_32000)
|
|
fs = IT6621_AES3_CON_FS_256000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_44100)
|
|
fs = IT6621_AES3_CON_FS_352000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_48000)
|
|
fs = IT6621_AES3_CON_FS_384000;
|
|
else if (priv->audio_fs == IT6621_AES3_CON_FS_64000)
|
|
fs = IT6621_AES3_CON_FS_512000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_88200)
|
|
fs = IT6621_AES3_CON_FS_705000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_96000)
|
|
fs = IEC958_AES3_CON_FS_768000;
|
|
else
|
|
dev_err(priv->dev, "invalid fs and channel\n");
|
|
} else if (layout == HDMI_AUDIO_LAYOUT_DSD_12CH) {
|
|
if (priv->audio_fs == IEC958_AES3_CON_FS_32000)
|
|
fs = IT6621_AES3_CON_FS_512000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_44100)
|
|
fs = IT6621_AES3_CON_FS_705000;
|
|
else if (priv->audio_fs == IEC958_AES3_CON_FS_48000)
|
|
fs = IEC958_AES3_CON_FS_768000;
|
|
else
|
|
dev_err(priv->dev, "invalid fs and channel\n");
|
|
}
|
|
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST3,
|
|
((fs & 0x30) << 2) + (fs & 0x0f));
|
|
|
|
/* Refer to HDMI2.1 spec table 9-28 and CTA861-G table 28~30 */
|
|
/* Audio InfoFrame */
|
|
if (priv->audio_ch > 8) {
|
|
#ifdef _1QD980ATC_ // for 5-1-60
|
|
ca = 0x00;
|
|
#else
|
|
/*
|
|
* CTA-861-G spec. Section 6.6.3: Delivery According to the
|
|
* Speaker Mask (Byte 4 = 0xFE).
|
|
*/
|
|
ca = 0xfe;
|
|
#endif
|
|
} else if ((priv->audio_type == IT6621_AUD_TYPE_NLPCM) ||
|
|
(priv->mch_lpcm_enabled == IT6621_TX_MCH_LPCM_EN) ||
|
|
(priv->layout_2ch_enabled == IT6621_TX_2CH_LAYOUT_EN)) {
|
|
ca = 0x00;
|
|
} else {
|
|
/*
|
|
* CTA-861-G spec. Table 35 Audio InfoFrame Data Byte 4.
|
|
* 0x00: FR/FL
|
|
* 0x01: FR/FL/LFE1
|
|
* 0x03: FR/FL/LFE1/FC
|
|
* 0x07: FR/FL/LFE1/FC/BC
|
|
* 0x0B: FR/FL/LFE1/FC/LS/RS
|
|
* 0x0F: FR/FL/LFE1/FC/LS/RS/BC
|
|
* 0x13: FR/FL/LFE1/FC/LS/RS/RLC/RRC
|
|
* 0xff: Channels delivered according to Channel Index
|
|
*/
|
|
|
|
switch (priv->audio_ch) {
|
|
case 0:
|
|
ca = 0xff;
|
|
break; // no audio
|
|
case 2:
|
|
ca = 0x00;
|
|
break;
|
|
case 3:
|
|
ca = 0x01;
|
|
break; // 0x01,0x02,0x04
|
|
case 4:
|
|
ca = 0x03;
|
|
break; // 0x03,0x05,0x06,0x08,0x14
|
|
case 5:
|
|
ca = 0x07;
|
|
break; // 0x07,0x09,0x0A,0x0C,0x15,0x16,0x18
|
|
case 6:
|
|
ca = 0x0B;
|
|
break; // 0x0B,0x0D,0x0E,0x10,0x17,0x19,0x1A,0x1C
|
|
case 7:
|
|
ca = 0x0f;
|
|
break; // 0x0F,0x11,0x12,0x1B,0x1D,0x1E
|
|
case 8:
|
|
ca = 0x13;
|
|
break; // 0x13,0x1F
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* For allocation test 5-1-34, can't use on normal LPCM test */
|
|
if (priv->force_ca & 0x80) {
|
|
switch (priv->force_ca) {
|
|
case 0x80:
|
|
ca = 0x00;
|
|
break; // 2ch
|
|
case 0x81:
|
|
ca = 0x01;
|
|
break; // 4ch
|
|
case 0x82:
|
|
ca = 0x0B;
|
|
break; // 6ch
|
|
case 0x83:
|
|
ca = 0x13;
|
|
break; // 8ch
|
|
default:
|
|
break;
|
|
}
|
|
|
|
/* Clear for test */
|
|
priv->force_ca = 0;
|
|
}
|
|
|
|
/* NOTE: Set channel allocation. */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST9, ca);
|
|
|
|
/*
|
|
* NOTE: DM_INH = 0, permitted or no information about any assertion
|
|
* of the down mixed stereo output.
|
|
*
|
|
* LSV3 = 0, LSV2 = 0, LSV1 = 0, LSV1 = 0, Level Shift Value is 0dB.
|
|
*
|
|
* LFEPBL1 = 0, LFEPBL0 = 0, unknown or refer to other information for
|
|
* LFE playback level comparing with other channel signal.
|
|
*/
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST10, 0x00);
|
|
|
|
if (priv->audio_ch > 8) {
|
|
/*
|
|
* CTA-861-G spec. Table 29: Audio InfoFrame Format When Byte 4
|
|
* is 0xFE.
|
|
*
|
|
* Byte 6: FLW/ RLC/ FLC/ BC BL/ FC LFE1 FL/
|
|
* FRW RRC FRC BR FR
|
|
* Byte 7: TpSiL/ SiL/ TpBC LFE2 LS/ TpFC TpC TpFL/
|
|
* TpSiR SiR RS TpFR
|
|
* Byte 8: F87=0 F86=0 F85=0 F84=0 TpLS/ BtFL/ BtFC TpBL/
|
|
* TpRS BtFR TpBR
|
|
*/
|
|
/* Set HDMI2.1 channel status */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x6f);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x0f);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x0c);
|
|
} else {
|
|
/* Reserved in CTA-861-G spec when Byte 4 is less than 0x32. */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST11, 0x00);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST12, 0x00);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST13, 0x00);
|
|
}
|
|
|
|
/* Reserved in CTA-861-G spec. */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST14, 0x00);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_CH_ST15, 0x00);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int it6621_set_arc_enabled(struct it6621_priv *priv, bool enabled)
|
|
{
|
|
priv->arc_enabled = enabled ? IT6621_TX_ARC_EN : IT6621_TX_ARC_DIS;
|
|
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_ARC_SEL,
|
|
priv->arc_enabled);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int it6621_set_earc_enabled(struct it6621_priv *priv, bool enabled)
|
|
{
|
|
priv->earc_enabled = enabled ? IT6621_TX_EARC_EN : IT6621_TX_EARC_DIS;
|
|
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0, IT6621_TX_EARC_SEL,
|
|
priv->earc_enabled);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int it6621_set_enter_arc(struct it6621_priv *priv, bool enabled)
|
|
{
|
|
unsigned int state;
|
|
|
|
if (enabled) {
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0,
|
|
IT6621_TX_ARC_NOW_SEL,
|
|
IT6621_TX_ARC_NOW_EN);
|
|
it6621_get_ddfsm_state(priv, &state);
|
|
if (state != IT6621_TX_ARC_MODE) {
|
|
dev_err(priv->dev, "not in ARC mode\n");
|
|
return -EAGAIN;
|
|
}
|
|
|
|
/* NOTE: ARC only support SPDIF */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_SRC_SEL,
|
|
IT6621_TX_AUD_SRC, IT6621_AUD_SRC_SPDIF);
|
|
/* Common mode ARC */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3,
|
|
IT6621_TX_IN_ARC_MODE_SEL,
|
|
IT6621_TX_IN_ARC_COMMON_MODE);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3,
|
|
IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_7);
|
|
dev_dbg(priv->dev, "ARC now enabled\n");
|
|
} else {
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0,
|
|
IT6621_TX_ARC_NOW_SEL,
|
|
IT6621_TX_ARC_NOW_DIS);
|
|
/* Signal mode ARC */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3,
|
|
IT6621_TX_IN_ARC_MODE_SEL,
|
|
IT6621_TX_IN_ARC_SIGNAL_MODE);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3,
|
|
IT6621_TX_DRV_CSW_SEL, IT6621_TX_DRV_CSW_4);
|
|
dev_dbg(priv->dev, "ARC now disabled\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int it6621_toggle_real_hpd(struct it6621_priv *priv)
|
|
{
|
|
/* toggle real HPD at least 100ms */
|
|
/* Set HPDB low */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1,
|
|
IT6621_TX_FORCE_HPDB_LOW_SEL,
|
|
IT6621_TX_FORCE_HPDB_LOW_EN);
|
|
msleep(120);
|
|
/* Set HPDB high */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1,
|
|
IT6621_TX_FORCE_HPDB_LOW_SEL,
|
|
IT6621_TX_FORCE_HPDB_LOW_DIS);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int it6621_set_auto_mode(struct it6621_priv *priv)
|
|
{
|
|
/* auto mode , eARC auto detect */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3,
|
|
IT6621_TX_FORCE_ARC_MODE_SEL,
|
|
IT6621_TX_FORCE_ARC_MODE_DIS);
|
|
|
|
it6621_set_enter_arc(priv, false);
|
|
|
|
return it6621_toggle_real_hpd(priv);
|
|
}
|
|
|
|
static int it6621_force_arc_mode(struct it6621_priv *priv)
|
|
{
|
|
/*
|
|
* Force ARC mode , close eARC mode.
|
|
* Please recover to this HDMI RX's original EDID.
|
|
*/
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3,
|
|
IT6621_TX_FORCE_ARC_MODE_SEL,
|
|
IT6621_TX_FORCE_ARC_MODE_EN);
|
|
|
|
return it6621_toggle_real_hpd(priv);
|
|
}
|
|
|
|
int it6621_get_ddfsm_state(struct it6621_priv *priv, unsigned int *state)
|
|
{
|
|
int ret;
|
|
|
|
ret = regmap_read(priv->regmap, IT6621_REG_TX_DD2, state);
|
|
*state &= IT6621_TX_DD_FSM_STATE;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int it6621_wait_cmdc_bus(struct it6621_priv *priv)
|
|
{
|
|
unsigned int status;
|
|
unsigned int cmdc_state;
|
|
unsigned int dd_state;
|
|
unsigned int val;
|
|
int ret;
|
|
|
|
ret = regmap_read_poll_timeout(priv->regmap, IT6621_REG_INT_STATUS1,
|
|
status, status & (IT6621_TX_CMD_FAIL |
|
|
IT6621_TX_CMD_DONE),
|
|
1000, 10000);
|
|
if (ret) {
|
|
it6621_get_ddfsm_state(priv, &dd_state);
|
|
regmap_read(priv->regmap, IT6621_REG_CMDC1, &val);
|
|
cmdc_state = val & IT6621_TX_CMDC_STATE;
|
|
dev_err(priv->dev, "timeout! TXDDFSM: %d, TXCMDFSM: %d\n",
|
|
dd_state, cmdc_state);
|
|
}
|
|
|
|
if (status & IT6621_TX_CMD_DONE) {
|
|
/* TX init done interrupt */
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS1,
|
|
IT6621_TX_CMD_DONE);
|
|
return 0;
|
|
}
|
|
|
|
if (status & IT6621_TX_CMD_FAIL) {
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS1,
|
|
IT6621_TX_CMD_FAIL);
|
|
dev_err(priv->dev, "TX CMD failed\n");
|
|
|
|
regmap_read(priv->regmap, IT6621_REG_CMDC1, &val);
|
|
|
|
if (val & IT6621_TX_FAIL_STATE_NO_RESP)
|
|
dev_err(priv->dev, "no response\n");
|
|
|
|
if (val & IT6621_TX_FAIL_STATE_UNEXP_RESP)
|
|
dev_err(priv->dev, "unexpected response\n");
|
|
|
|
if (val & IT6621_TX_FAIL_STATE_ECC_ERR)
|
|
dev_err(priv->dev, "uncorrectable ECC error\n");
|
|
|
|
if (val & IT6621_TX_FAIL_STATE_TIMEOUT) {
|
|
if (priv->cmd_to_enabled)
|
|
dev_err(priv->dev,
|
|
"NACK/RETRY 256 times timeout\n");
|
|
else
|
|
dev_err(priv->dev, "NACK command state\n");
|
|
}
|
|
}
|
|
|
|
return -EAGAIN;
|
|
}
|
|
|
|
static int it6621_read_cmdc_cmd(struct it6621_priv *priv, unsigned int devid,
|
|
unsigned int offset, unsigned int *cmd)
|
|
{
|
|
unsigned int state;
|
|
|
|
it6621_get_ddfsm_state(priv, &state);
|
|
if (state != IT6621_TX_EARC_MODE) {
|
|
dev_err(priv->dev, "abort CMDC read\n");
|
|
return -EAGAIN;
|
|
}
|
|
|
|
/* Data FIFO Clear */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC3,
|
|
IT6621_TX_DATA_FIFO_CLEAR,
|
|
IT6621_TX_DATA_FIFO_CLEAR);
|
|
/* TxCmd DevID */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid);
|
|
/* TxCmd Offset */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset);
|
|
/* Read Trigger (1-byte) */
|
|
regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_READ_TRIGGER);
|
|
|
|
it6621_wait_cmdc_bus(priv);
|
|
|
|
return regmap_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, cmd);
|
|
}
|
|
|
|
static void it6621_write_cmdc_cmd(struct it6621_priv *priv, unsigned int devid,
|
|
unsigned int offset, unsigned int data)
|
|
{
|
|
unsigned int state;
|
|
|
|
it6621_get_ddfsm_state(priv, &state);
|
|
if (state != IT6621_TX_EARC_MODE) {
|
|
dev_err(priv->dev, "abort CMDC write\n");
|
|
return;
|
|
}
|
|
|
|
/* Data FIFO Clear */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC3,
|
|
IT6621_TX_DATA_FIFO_CLEAR,
|
|
IT6621_TX_DATA_FIFO_CLEAR);
|
|
/* TxCmd DevID */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid);
|
|
/* TxCmd Offset */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset);
|
|
/* TxCmd WrData */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_DATA_FIFO, data);
|
|
/* Write Trigger (1-byte) */
|
|
regmap_write(priv->regmap, IT6621_REG_CMDC2, IT6621_TX_WRITE_TRIGGER);
|
|
|
|
it6621_wait_cmdc_bus(priv);
|
|
}
|
|
|
|
static int it6621_read_cmdc_bulk(struct it6621_priv *priv, unsigned int devid,
|
|
unsigned int offset, size_t len, void *data)
|
|
{
|
|
unsigned int state;
|
|
int ret;
|
|
|
|
it6621_get_ddfsm_state(priv, &state);
|
|
if (state != IT6621_TX_EARC_MODE) {
|
|
dev_err(priv->dev, "abort CMDC bulk read\n");
|
|
return -EAGAIN;
|
|
}
|
|
|
|
/* Data FIFO Clear */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC3,
|
|
IT6621_TX_DATA_FIFO_CLEAR,
|
|
IT6621_TX_DATA_FIFO_CLEAR);
|
|
/* TxCmd DevID */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_DEV_ID, devid);
|
|
/* TxCmd Offset */
|
|
regmap_write(priv->regmap, IT6621_REG_TX_OFFSET, offset);
|
|
/* Read Trigger & Read ByteNum[4:0] */
|
|
regmap_write(priv->regmap, IT6621_REG_CMDC2,
|
|
IT6621_TX_READ_TRIGGER | (len - 1));
|
|
|
|
ret = it6621_wait_cmdc_bus(priv);
|
|
if (ret)
|
|
return ret;
|
|
|
|
regmap_noinc_read(priv->regmap, IT6621_REG_TX_DATA_FIFO, data, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* it6621_set_latency - eARC TX Set latency request
|
|
*
|
|
* @latency: latency in marco second, range from 0 to 250 ms.
|
|
*/
|
|
static void it6621_set_latency(struct it6621_priv *priv, unsigned int latency)
|
|
{
|
|
it6621_write_cmdc_cmd(priv, 0x74, 0xd3, latency);
|
|
}
|
|
|
|
/**
|
|
* it6621_get_latency - Read eARC RX's Latency
|
|
*
|
|
* @latency: latency in marco second, range from 0 to 250 ms.
|
|
*/
|
|
static int it6621_get_latency(struct it6621_priv *priv, unsigned int *latency)
|
|
{
|
|
return it6621_read_cmdc_cmd(priv, 0x74, 0xd2, latency);
|
|
}
|
|
|
|
/**
|
|
* it6621_reset_driver - should be set power down in ARC mode
|
|
*
|
|
* @on: power on/down differential mode signal.
|
|
*/
|
|
static void it6621_reset_driver(struct it6621_priv *priv, bool enabled)
|
|
{
|
|
dev_dbg(priv->dev, "set TX driver %s\n", enabled ? "on" : "off");
|
|
|
|
if (enabled)
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_RESET_SEL,
|
|
IT6621_TX_DRV_RESET_DIS);
|
|
else
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_RESET_SEL,
|
|
IT6621_TX_DRV_RESET_EN);
|
|
}
|
|
|
|
static int it6621_check_audio(struct it6621_priv *priv)
|
|
{
|
|
unsigned int val;
|
|
|
|
if (test_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag) &&
|
|
test_bit(IT6621_AUDIO_START, &priv->audio_flag)) {
|
|
if (test_bit(IT6621_EARC_BCLK_OK, &priv->events)) {
|
|
/* Need to be finetune at diff platform */
|
|
msleep(50);
|
|
it6621_reset_driver(priv, true);
|
|
clear_bit(IT6621_EARC_BCLK_OK, &priv->events);
|
|
clear_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag);
|
|
regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val);
|
|
dev_dbg(priv->dev, "A2: 0x%02x\n", val);
|
|
}
|
|
|
|
if (priv->force_arc)
|
|
it6621_set_enter_arc(priv, true);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int it6621_earc_init(struct it6621_priv *priv)
|
|
{
|
|
priv->state = IT6621_EARC_IDLE;
|
|
priv->rclk = 0;
|
|
priv->aclk = 0;
|
|
priv->bclk = 0;
|
|
|
|
/* Enable GRCLK */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0,
|
|
IT6621_GATE_RCLK_SEL, IT6621_GATE_RCLK_DIS);
|
|
|
|
/* TXAFE PLL Reset */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE0,
|
|
IT6621_TX_XP_RESET_SEL, IT6621_TX_XP_RESET_ACTIVE);
|
|
|
|
/* eARCTX Reset */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET,
|
|
IT6621_SW_RCLK_RESET_SEL, IT6621_SW_RCLK_RESET_EN);
|
|
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL0,
|
|
IT6621_RCLK_FREQ_SEL, priv->rclk_sel);
|
|
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7,
|
|
IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_DIS);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7,
|
|
IT6621_UPDATE_AVG_EN_SEL, priv->update_avg_enabled);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC4,
|
|
IT6621_TX_HB_RETRY_TIME_SEL |
|
|
IT6621_TX_HB_RETRY_SEL,
|
|
priv->hb_retry_sel | priv->hb_retry_enabled);
|
|
/* NOTE: Disable to pass SL-870 HFR5-1-35/36/37 */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC5,
|
|
IT6621_TX_AUTO_WRITE_STATE_SEL,
|
|
IT6621_TX_AUTO_WRITE_STATE_DIS);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL0,
|
|
IT6621_TX_ENC_OPT | IT6621_TX_ENC_SEL |
|
|
IT6621_TX_ECC_OPT,
|
|
priv->enc_opt | (priv->audio_enc << 3) |
|
|
priv->ecc_opt);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_LOW,
|
|
priv->enc_seed & 0xff);
|
|
regmap_write(priv->regmap, IT6621_REG_TX_ENC_SEED_HIGH,
|
|
(priv->enc_seed & 0xff00) >> 8);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_DMAC_CTRL1,
|
|
IT6621_TX_U_BIT_OPT | IT6621_TX_C_CH_OPT |
|
|
IT6621_TX_PKT3_EN_SEL | IT6621_TX_PKT2_EN_SEL |
|
|
IT6621_TX_PKT1_EN_SEL,
|
|
priv->ubit_opt | priv->c_ch_opt |
|
|
priv->pkt3_enabled | priv->pkt2_enabled |
|
|
priv->pkt1_enabled);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC6,
|
|
IT6621_TX_RESYNC_OPT | IT6621_TX_FORCE_CMO_OPT |
|
|
IT6621_TX_CMO_OPT,
|
|
priv->resync_opt | priv->force_cmo_enabled |
|
|
priv->cmo_opt);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC0,
|
|
IT6621_TX_TURN_OVER_SEL |
|
|
IT6621_TX_NEXT_PKT_TIMEOUT_SEL,
|
|
priv->turn_over_sel |
|
|
priv->nxt_pkt_to_sel);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AUD_CTRL10,
|
|
IT6621_TX_2CH_LAYOUT_SEL | IT6621_TX_NLPCM_I2S_SEL |
|
|
IT6621_TX_MCH_LPCM_SEL | IT6621_TX_EXT_MUTE_SEL,
|
|
priv->layout_2ch_enabled | priv->i2s_nlpcm_enabled |
|
|
priv->mch_lpcm_enabled | IT6621_TX_EXT_MUTE_DIS);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CLK_CTRL2,
|
|
IT6621_BCLK_INV_SEL | IT6621_ACLK_INV_SEL,
|
|
priv->bclk_inv_enabled | IT6621_ACLK_INV_DIS);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0,
|
|
IT6621_TX_ARC_NOW_SEL | IT6621_TX_ARC_SEL |
|
|
IT6621_TX_EARC_SEL,
|
|
priv->enter_arc_now | priv->arc_enabled |
|
|
priv->earc_enabled);
|
|
|
|
if (priv->force_arc)
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3,
|
|
IT6621_TX_FORCE_ARC_MODE_SEL,
|
|
IT6621_TX_FORCE_ARC_MODE_EN);
|
|
else
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD3,
|
|
IT6621_TX_FORCE_ARC_MODE_SEL,
|
|
IT6621_TX_FORCE_ARC_MODE_DIS);
|
|
|
|
/* test to disable TxXPLOCKChgInt */
|
|
regmap_write(priv->regmap, IT6621_REG_INT_EN0,
|
|
IT6621_TX_RESYNC_ERR_EN | IT6621_TX_NO_AUD_CHANGE_EN |
|
|
IT6621_TX_DISV_TIMEOUT_EN | IT6621_TX_HB_LOST_EN |
|
|
IT6621_TX_STATE3_CHANGE_EN | IT6621_TX_HPDIO_OFF_EN |
|
|
IT6621_TX_HPDIO_ON_EN);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_EN1,
|
|
IT6621_TX_CMD_DONE_EN | IT6621_TX_CMD_FAIL_EN |
|
|
IT6621_TX_READ_STATE_CHG_EN | IT6621_TX_CMDC_BP_ERR_EN |
|
|
IT6621_TX_WRITE_STATE_CHG_EN | IT6621_TX_WRITE_CAP_CHG_EN |
|
|
IT6621_TX_HB_FAIL_EN);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_EN2,
|
|
IT6621_TX_MUTE_CHANGE_EN | IT6621_TX_SPDIF_CHANGE_EN |
|
|
IT6621_TX_SPDIF_READY_EN | IT6621_TX_DEC_ERR_EN |
|
|
IT6621_TX_FIFO_ERR_EN);
|
|
/* enable RX HPD interrupt for HPDB interrupt */
|
|
regmap_write(priv->regmap, IT6621_REG_INT_EN3,
|
|
IT6621_TX_HPDB_OFF_EN | IT6621_TX_HPDB_ON_EN);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_EN4,
|
|
IT6621_DET_NO_BCLK_EN | IT6621_DET_BCLK_VALID_EN |
|
|
IT6621_DET_BCLK_STABLE_EN | IT6621_DET_ACLK_VALID_EN |
|
|
IT6621_DET_ACLK_STABLE_EN);
|
|
regmap_update_bits(priv->regmap, 0xa9, 0xFF, 0xFD);
|
|
it6621_calc_rclk(priv);
|
|
|
|
/* enable ACLK detection */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CLK_DET7,
|
|
IT6621_ACLK_DET_EN_SEL, IT6621_ACLK_DET_EN);
|
|
|
|
/* RTxDbgFifoClr */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DEBUG_FIFO2,
|
|
IT6621_TX_DEBUG_FIFO_CLEAR_SEL,
|
|
IT6621_TX_DEBUG_FIFO_CLEAR_EN);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE1,
|
|
IT6621_TX_XP_ER0_SEL | IT6621_TX_XP_DEI_SEL,
|
|
IT6621_TX_XP_ER0_DIS | IT6621_TX_XP_DEI_DIS);
|
|
if (priv->revid == IT6621_REVISION_VARIANT_C0) {
|
|
/*
|
|
* NOTE: In eARC mode, change DMAC back to B0 version,
|
|
* DRV_OT_SEL set to 1 for C0,TX_HYS_SEL = 5 for C0
|
|
*/
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_OT_SEL |
|
|
IT6621_TX_DRV_DSW_SEL |
|
|
IT6621_TX_DRV_DC,
|
|
IT6621_TX_DRV_OT_EN |
|
|
IT6621_TX_DRV_DSW_4 |
|
|
IT6621_TX_DRV_DC_SEL_DIS |
|
|
IT6621_TX_DRV_DC_DIS);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4,
|
|
IT6621_TX_HYS_SEL |
|
|
IT6621_TX_VCM_SEL |
|
|
IT6621_TX_RC_CK_SEL,
|
|
IT6621_TX_HYS5 |
|
|
priv->vcm_sel |
|
|
IT6621_TX_RC_CK_DIS);
|
|
} else if (priv->revid == IT6621_REVISION_VARIANT_D0) {
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_OT_SEL |
|
|
IT6621_TX_DRV_DSW_SEL |
|
|
IT6621_TX_DRV_DC,
|
|
IT6621_TX_DRV_OT_EN |
|
|
IT6621_TX_DRV_DSW_7 |
|
|
IT6621_TX_DRV_DC_SEL_DIS |
|
|
IT6621_TX_DRV_DC_DIS);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4,
|
|
IT6621_TX_HYS_SEL |
|
|
IT6621_TX_VCM_SEL |
|
|
IT6621_TX_RC_CK_SEL,
|
|
IT6621_TX_HYS5 |
|
|
priv->vcm_sel |
|
|
IT6621_TX_RC_CK_DIS);
|
|
} else {
|
|
/*
|
|
* NOTE: DRV_OT_SEL set to 0 force TM tri-state in
|
|
* ARC single mode (B0).
|
|
*/
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_OT_SEL |
|
|
IT6621_TX_DRV_DSW_SEL,
|
|
IT6621_TX_DRV_OT_DIS |
|
|
IT6621_TX_DRV_DSW_4);
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE4,
|
|
IT6621_TX_HYS_SEL |
|
|
IT6621_TX_VCM_SEL |
|
|
IT6621_TX_RC_CK_SEL,
|
|
IT6621_TX_HYS6 |
|
|
priv->vcm_sel |
|
|
IT6621_TX_RC_CK_DIS);
|
|
}
|
|
|
|
/* For D0 TX_DRV_CSR */
|
|
if (priv->revid == IT6621_REVISION_VARIANT_D0)
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3,
|
|
IT6621_TX_DRV_CSW_SEL |
|
|
IT6621_TX_DRV_CSR_SEL,
|
|
IT6621_TX_DRV_CSW_4 |
|
|
IT6621_TX_DRV_CSR_2);
|
|
else
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE3,
|
|
IT6621_TX_DRV_CSW_SEL |
|
|
IT6621_TX_DRV_CSR_SEL,
|
|
IT6621_TX_DRV_CSW_4 |
|
|
IT6621_TX_DRV_CSR_4);
|
|
|
|
regmap_update_bits(priv->regmap, IT6621_REG_SYS_RESET,
|
|
IT6621_SW_RCCLK_RESET_SEL |
|
|
IT6621_SW_TCCLK_RESET_SEL |
|
|
IT6621_SW_BCLK_RESET_SEL |
|
|
IT6621_SW_ACLK_RESET_SEL,
|
|
IT6621_SW_RCCLK_RESET_DIS |
|
|
IT6621_SW_TCCLK_RESET_DIS |
|
|
IT6621_SW_BCLK_RESET_DIS |
|
|
IT6621_SW_ACLK_RESET_DIS);
|
|
|
|
/* Enable eARC TX Discovery and Disconnect FSM */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_DD0,
|
|
IT6621_TX_DD_FSM_SEL, IT6621_TX_DD_FSM_EN);
|
|
|
|
if (priv->force_arc) {
|
|
dev_info(priv->dev, "force ARC mode\n");
|
|
it6621_force_arc_mode(priv);
|
|
}
|
|
|
|
if (priv->force_earc) {
|
|
dev_info(priv->dev, "force eARC mode\n");
|
|
it6621_set_auto_mode(priv);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int it6621_read_rxcap(struct it6621_priv *priv)
|
|
{
|
|
u8 rxcap[IT6621_RX_CAP_MAX_LEN];
|
|
int i;
|
|
int ret;
|
|
|
|
/* Enable eARC TX Command Done/Fail Interrupt */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_INT_EN1,
|
|
IT6621_TX_CMD_FAIL_SEL | IT6621_TX_CMD_DONE_SEL,
|
|
IT6621_TX_CMD_FAIL_EN | IT6621_TX_CMD_DONE_EN);
|
|
|
|
for (i = 0; i < 255; i += IT6621_RXCAP_BULK_LEN) {
|
|
ret = it6621_read_cmdc_bulk(priv, 0xa0, i,
|
|
IT6621_RXCAP_BULK_LEN, &rxcap[i]);
|
|
if (ret) {
|
|
dev_err(priv->dev, "failed to read eARC RX Cap\n");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
mutex_lock(&priv->rxcap_lock);
|
|
|
|
if (memcmp(rxcap, priv->rxcap, sizeof(priv->rxcap))) {
|
|
memcpy(priv->rxcap, rxcap, sizeof(priv->rxcap));
|
|
set_bit(IT6621_EARC_CAP_CHG, &priv->events);
|
|
}
|
|
|
|
mutex_unlock(&priv->rxcap_lock);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void it6621_set_state(struct it6621_priv *priv, unsigned int state)
|
|
{
|
|
if (priv->state != state) {
|
|
priv->state = state;
|
|
it6621_uapi_msg(priv, IT6621_EVENT_STATE_CHANGE, &priv->state,
|
|
sizeof(priv->state));
|
|
}
|
|
}
|
|
|
|
static int it6621_check_rxcap(struct it6621_priv *priv)
|
|
{
|
|
if (test_bit(IT6621_EARC_CAP_CHG, &priv->events)) {
|
|
clear_bit(IT6621_EARC_CAP_CHG, &priv->events);
|
|
it6621_uapi_msg(priv, IT6621_EVENT_AUDIO_CAP_CHANGE,
|
|
priv->rxcap, sizeof(priv->rxcap));
|
|
cancel_work_sync(&priv->hpdio_work);
|
|
schedule_work(&priv->hpdio_work);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int it6621_earc_irq(struct it6621_priv *priv)
|
|
{
|
|
unsigned int status0;
|
|
unsigned int status1;
|
|
unsigned int status2;
|
|
unsigned int status3;
|
|
unsigned int status4;
|
|
unsigned int state;
|
|
unsigned int val;
|
|
unsigned int latency = 0;
|
|
|
|
regmap_read(priv->regmap, IT6621_REG_INT_STATUS0, &status0);
|
|
regmap_read(priv->regmap, IT6621_REG_INT_STATUS1, &status1);
|
|
regmap_read(priv->regmap, IT6621_REG_INT_STATUS2, &status2);
|
|
regmap_read(priv->regmap, IT6621_REG_INT_STATUS3, &status3);
|
|
regmap_read(priv->regmap, IT6621_REG_INT_STATUS4, &status4);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS0, status0);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS1, status1);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS2, status2);
|
|
status3 &= IT6621_TX_HPDB_OFF | IT6621_TX_HPDB_ON;
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS3, status3);
|
|
regmap_write(priv->regmap, IT6621_REG_INT_STATUS4, status4);
|
|
|
|
/* Interrupt status0 */
|
|
if (status0 & IT6621_TX_HPDIO_ON) {
|
|
dev_dbg(priv->dev, "HPD IO on\n");
|
|
/* Set HPDB low clear */
|
|
regmap_update_bits(priv->regmap, IT6621_REG_SYS_CTRL1,
|
|
IT6621_TX_FORCE_HPDB_LOW_SEL,
|
|
IT6621_TX_FORCE_HPDB_LOW_DIS);
|
|
}
|
|
|
|
if (status0 & IT6621_TX_HPDIO_OFF) {
|
|
dev_dbg(priv->dev, "HPD IO off\n");
|
|
|
|
if (test_bit(IT6621_ARC_START, &priv->events))
|
|
it6621_set_enter_arc(priv, false);
|
|
|
|
/* Set HPDB low */
|
|
if (!priv->toggle_by_edid)
|
|
regmap_update_bits(priv->regmap,
|
|
IT6621_REG_SYS_CTRL1,
|
|
IT6621_TX_FORCE_HPDB_LOW_SEL,
|
|
IT6621_TX_FORCE_HPDB_LOW_EN);
|
|
else
|
|
priv->toggle_by_edid = 0;
|
|
|
|
clear_bit(IT6621_ARC_START, &priv->events);
|
|
}
|
|
|
|
if (status0 & IT6621_TX_STATE3_CHANGE) {
|
|
dev_dbg(priv->dev, "eARC enable\n");
|
|
|
|
it6621_get_ddfsm_state(priv, &state);
|
|
dev_dbg(priv->dev, "eARC stat3 change to %d\n",
|
|
state & IT6621_TX_EARC_MODE ? 1 : 0);
|
|
clear_bit(IT6621_ARC_START, &priv->events);
|
|
|
|
if (state & IT6621_TX_EARC_MODE)
|
|
it6621_set_state(priv, IT6621_EARC_CONNECTED);
|
|
else
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_RESET_SEL,
|
|
IT6621_TX_DRV_RESET_EN);
|
|
}
|
|
|
|
if (status0 & IT6621_TX_HB_LOST) {
|
|
dev_dbg(priv->dev, "heartbeat lost\n");
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_RESET_SEL,
|
|
IT6621_TX_DRV_RESET_EN);
|
|
}
|
|
|
|
if (status0 & IT6621_TX_DISV_TIMEOUT) {
|
|
dev_dbg(priv->dev, "discovery timeout\n");
|
|
|
|
priv->events = 0;
|
|
set_bit(IT6621_ARC_START, &priv->events);
|
|
it6621_set_state(priv, IT6621_ARC_PENDING);
|
|
}
|
|
|
|
if (status0 & IT6621_TX_NO_AUD_CHANGE) {
|
|
regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val);
|
|
val &= IT6621_TX_NO_AUDIO;
|
|
dev_dbg(priv->dev, "TX has %s audio stream\n", val ? "no" : "");
|
|
}
|
|
|
|
if (status0 & IT6621_TX_XP_LOCK_CHANGE) {
|
|
regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val);
|
|
val &= IT6621_TX_XP_LOCK;
|
|
dev_dbg(priv->dev, "XP lock: %d\n", val >> 2);
|
|
}
|
|
|
|
if (status0 & IT6621_TX_RESYNC_ERR)
|
|
dev_err(priv->dev, "CMDC resync error\n");
|
|
|
|
/* Interrupt status1 */
|
|
if (status1 & IT6621_TX_CMD_DONE)
|
|
dev_dbg(priv->dev, "Cmd Done\n");
|
|
|
|
if (status1 & IT6621_TX_HB_DONE)
|
|
dev_dbg(priv->dev, "heartbeat done\n");
|
|
|
|
if (status1 & IT6621_TX_READ_STATE_CHANGE) {
|
|
regmap_read(priv->regmap, IT6621_REG_TX_READ_STATE, &val);
|
|
dev_dbg(priv->dev, "RX state change to 0x%02X\n", val);
|
|
val &= 0x18;
|
|
regmap_update_bits(priv->regmap, IT6621_REG_CMDC5, 0x18, val);
|
|
}
|
|
|
|
if (status1 & IT6621_TX_CMDC_BP_ERR)
|
|
dev_err(priv->dev, "CMDC bi-phase error\n");
|
|
|
|
if (status1 & IT6621_TX_WRITE_STATE_CHANGE) {
|
|
it6621_get_latency(priv, &latency);
|
|
dev_dbg(priv->dev, "auto write STAT_CHNG 1->0 done\n");
|
|
dev_dbg(priv->dev, "latency: 0x%02X ms\n", latency);
|
|
}
|
|
|
|
if (status1 & IT6621_TX_WRITE_CAP_CHANGE) {
|
|
dev_dbg(priv->dev, "auto write CAP_CHNG 1->0 done\n");
|
|
it6621_read_rxcap(priv);
|
|
|
|
if (priv->audio_enc) {
|
|
it6621_write_cmdc_cmd(priv, 0x9c, 0x10,
|
|
priv->enc_opt >> 4);
|
|
it6621_write_cmdc_cmd(priv, 0x9c, 0x11,
|
|
priv->enc_seed & 0xff);
|
|
it6621_write_cmdc_cmd(priv, 0x9c, 0x12,
|
|
(priv->enc_seed & 0xff00) >> 8);
|
|
}
|
|
|
|
/* Write 140ms to ERX_LATENCY_REQ */
|
|
it6621_set_latency(priv, 140);
|
|
regmap_read(priv->regmap, IT6621_REG_TX_AFE2, &val);
|
|
val &= IT6621_TX_DRV_RESET_SEL;
|
|
dev_dbg(priv->dev, "TX driver reset: %d\n", val >> 1);
|
|
}
|
|
|
|
if (status1 & IT6621_TX_HB_FAIL)
|
|
dev_dbg(priv->dev, "heartbeat fail\n");
|
|
|
|
/* Interrupt status2 */
|
|
if (status2 & IT6621_TX_FIFO_ERR)
|
|
dev_dbg(priv->dev, "audio FIFO error\n");
|
|
|
|
if (status2 & IT6621_TX_DEC_ERR)
|
|
dev_dbg(priv->dev, "audio decode error\n");
|
|
|
|
if (status2 & IT6621_TX_SPDIF_READY)
|
|
dev_dbg(priv->dev, "SPDIF channel status is ready\n");
|
|
|
|
if (status2 & IT6621_TX_SPDIF_CHANGE)
|
|
dev_dbg(priv->dev, "SPDIF channel status is changed\n");
|
|
|
|
if (status2 & IT6621_TX_MUTE_CHANGE) {
|
|
regmap_read(priv->regmap, IT6621_REG_SYS_STATUS, &val);
|
|
val &= IT6621_TX_MUTE;
|
|
dev_dbg(priv->dev, "input is %s\n", val ? "muted" : "unmuted");
|
|
}
|
|
|
|
/* Interrupt status3 */
|
|
if (status3 & IT6621_TX_HPDB_ON) {
|
|
dev_dbg(priv->dev, "HPD bus on\n");
|
|
it6621_set_state(priv, IT6621_EARC_PENDING);
|
|
}
|
|
|
|
if (status3 & IT6621_TX_HPDB_OFF) {
|
|
dev_dbg(priv->dev, "HPD bus off\n");
|
|
regmap_update_bits(priv->regmap, IT6621_REG_TX_AFE2,
|
|
IT6621_TX_DRV_RESET_SEL,
|
|
IT6621_TX_DRV_RESET_EN);
|
|
|
|
if (test_bit(IT6621_ARC_START, &priv->events))
|
|
it6621_set_enter_arc(priv, false);
|
|
|
|
clear_bit(IT6621_ARC_START, &priv->events);
|
|
it6621_set_state(priv, IT6621_EARC_IDLE);
|
|
}
|
|
|
|
/* Interrupt status4 */
|
|
if (status4 & IT6621_DET_ACLK_STABLE) {
|
|
dev_dbg(priv->dev, "ACLK is stable\n");
|
|
it6621_get_aclk(priv);
|
|
it6621_force_pdiv(priv);
|
|
}
|
|
|
|
if (status4 & IT6621_DET_ACLK_VALID)
|
|
dev_dbg(priv->dev, "ACLK is valid\n");
|
|
|
|
if (status4 & IT6621_DET_NO_BCLK) {
|
|
dev_dbg(priv->dev, "BCLK is not present\n");
|
|
clear_bit(IT6621_EARC_BCLK_OK, &priv->events);
|
|
it6621_reset_driver(priv, false);
|
|
}
|
|
|
|
if (status4 & IT6621_DET_BCLK_STABLE) {
|
|
dev_dbg(priv->dev, "BCLK is stable\n");
|
|
it6621_get_bclk(priv);
|
|
set_bit(IT6621_EARC_BCLK_OK, &priv->events);
|
|
if (test_bit(IT6621_AUDIO_START, &priv->audio_flag))
|
|
set_bit(IT6621_AUDIO_TO_EN_DMAC, &priv->audio_flag);
|
|
}
|
|
|
|
if (status4 & IT6621_DET_BCLK_VALID)
|
|
dev_dbg(priv->dev, "BCLK is valid\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
irqreturn_t it6621_irq(int irq, void *data)
|
|
{
|
|
struct it6621_priv *priv = data;
|
|
|
|
it6621_earc_irq(priv);
|
|
|
|
it6621_check_audio(priv);
|
|
it6621_check_rxcap(priv);
|
|
|
|
return IRQ_HANDLED;
|
|
}
|