ASoC: rockchip: sai: Add support for CLK-ALWAYS-ON quirks

This patch add support for keeping BCLK / FSYNC always on.
it's required by some devices, such as HDMI, PA, etc.

For example: on HDMI situation

There are some TVs require maintaining N/CTS packets or AUDS
packets to keep audio logic active, otherwise, the first tone
may be lost.

In order to optimize the user experience, we need to ensure
continuous transmission of N/CTS and AUDS packets from the
HDMI-TX, so that the SINK TV devices can maintain audio logic
activation, promptly process audio data, and achieve the
completeness of the first tone.

We init a 48k I2S-STANDARD clock timing as default.

Change-Id: I298b0ad2d53bdc41927f567c2af481f2a0bd5422
Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com>
This commit is contained in:
Sugar Zhang 2023-03-28 22:15:51 +08:00
parent 49bf5942cf
commit 54b0bc7bac

View File

@ -26,6 +26,9 @@
#define FW_RATIO_MIN 1
#define MAXBURST_PER_FIFO 8
#define DEFAULT_FS 48000
#define QUIRK_ALWAYS_ON BIT(0)
enum fpw_mode {
FPW_ONE_BCLK_WIDTH,
FPW_ONE_SLOT_WIDTH,
@ -44,6 +47,7 @@ struct rk_sai_dev {
struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1];
unsigned int tx_lanes;
unsigned int rx_lanes;
unsigned int quirks;
enum fpw_mode fpw;
int fw_ratio;
bool has_capture;
@ -53,6 +57,16 @@ struct rk_sai_dev {
bool is_clk_auto;
};
static const struct sai_of_quirks {
char *quirk;
int id;
} of_quirks[] = {
{
.quirk = "rockchip,always-on",
.id = QUIRK_ALWAYS_ON,
},
};
static int sai_runtime_suspend(struct device *dev)
{
struct rk_sai_dev *sai = dev_get_drvdata(dev);
@ -1154,6 +1168,50 @@ static irqreturn_t rockchip_sai_isr(int irq, void *devid)
return IRQ_HANDLED;
}
static int rockchip_sai_keep_clk_always_on(struct rk_sai_dev *sai)
{
unsigned int mclk_rate, bclk_rate, div_bclk;
sai->is_master_mode = true;
/* init I2S fmt default */
rockchip_sai_fmt_create(sai, SND_SOC_DAIFMT_I2S);
regmap_update_bits(sai->regmap, SAI_FSCR,
SAI_FSCR_FW_MASK |
SAI_FSCR_FPW_MASK,
SAI_FSCR_FW(64) |
SAI_FSCR_FPW(32));
mclk_rate = clk_get_rate(sai->mclk);
bclk_rate = DEFAULT_FS * 64;
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
regmap_update_bits(sai->regmap, SAI_CKR, SAI_CKR_MDIV_MASK,
SAI_CKR_MDIV(div_bclk));
pm_runtime_forbid(sai->dev);
dev_info(sai->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n",
mclk_rate, bclk_rate, DEFAULT_FS);
return 0;
}
static int rockchip_sai_parse_quirks(struct rk_sai_dev *sai)
{
int ret = 0, i = 0;
for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
if (device_property_read_bool(sai->dev, of_quirks[i].quirk))
sai->quirks |= of_quirks[i].id;
if (sai->quirks & QUIRK_ALWAYS_ON)
ret = rockchip_sai_keep_clk_always_on(sai);
return ret;
}
static int rockchip_sai_probe(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
@ -1212,6 +1270,10 @@ static int rockchip_sai_probe(struct platform_device *pdev)
return PTR_ERR(sai->hclk);
}
ret = rockchip_sai_parse_quirks(sai);
if (ret)
return ret;
pm_runtime_enable(&pdev->dev);
if (!pm_runtime_enabled(&pdev->dev)) {
ret = sai_runtime_resume(&pdev->dev);