Skip to content

Commit a859bf6

Browse files
author
Sugar Zhang
committed
ASoC: rockchip: i2s: 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. Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com> Change-Id: Icdf2101c4117bc0ec4c05343e7317477cc02d6c0
1 parent 0fdec09 commit a859bf6

1 file changed

Lines changed: 66 additions & 4 deletions

File tree

sound/soc/rockchip/rockchip_i2s.c

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
#define CLK_PPM_MIN (-1000)
3232
#define CLK_PPM_MAX (1000)
3333

34+
#define DEFAULT_MCLK_FS 256
35+
#define DEFAULT_FS 48000
36+
37+
#define QUIRK_ALWAYS_ON BIT(0)
38+
3439
struct rk_i2s_pins {
3540
u32 reg_offset;
3641
u32 shift;
@@ -69,6 +74,17 @@ struct rk_i2s_dev {
6974
int clk_ppm;
7075
bool mclk_calibrate;
7176

77+
unsigned int quirks;
78+
};
79+
80+
static struct i2s_of_quirks {
81+
char *quirk;
82+
int id;
83+
} of_quirks[] = {
84+
{
85+
.quirk = "rockchip,always-on",
86+
.id = QUIRK_ALWAYS_ON,
87+
},
7288
};
7389

7490
static int i2s_runtime_suspend(struct device *dev)
@@ -182,7 +198,7 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
182198
regmap_update_bits(i2s->regmap, I2S_DMACR,
183199
I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
184200

185-
if (!i2s->rx_start) {
201+
if (!i2s->rx_start && !(i2s->quirks & QUIRK_ALWAYS_ON)) {
186202
regmap_update_bits(i2s->regmap, I2S_XFER,
187203
I2S_XFER_TXS_START |
188204
I2S_XFER_RXS_START,
@@ -214,7 +230,7 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
214230
regmap_update_bits(i2s->regmap, I2S_DMACR,
215231
I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
216232

217-
if (!i2s->tx_start) {
233+
if (!i2s->tx_start && !(i2s->quirks & QUIRK_ALWAYS_ON)) {
218234
regmap_update_bits(i2s->regmap, I2S_XFER,
219235
I2S_XFER_TXS_START |
220236
I2S_XFER_RXS_START,
@@ -773,6 +789,38 @@ static const struct of_device_id rockchip_i2s_match[] = {
773789
{},
774790
};
775791

792+
static int rockchip_i2s_keep_clk_always_on(struct rk_i2s_dev *i2s)
793+
{
794+
unsigned int mclk_rate = DEFAULT_FS * DEFAULT_MCLK_FS;
795+
unsigned int bclk_rate = i2s->bclk_fs * DEFAULT_FS;
796+
unsigned int div_lrck = i2s->bclk_fs;
797+
unsigned int div_bclk;
798+
799+
div_bclk = DIV_ROUND_CLOSEST(mclk_rate, bclk_rate);
800+
801+
/* assign generic freq */
802+
clk_set_rate(i2s->mclk, mclk_rate);
803+
804+
regmap_update_bits(i2s->regmap, I2S_CKR,
805+
I2S_CKR_MDIV_MASK,
806+
I2S_CKR_MDIV(div_bclk));
807+
regmap_update_bits(i2s->regmap, I2S_CKR,
808+
I2S_CKR_TSD_MASK |
809+
I2S_CKR_RSD_MASK,
810+
I2S_CKR_TSD(div_lrck) |
811+
I2S_CKR_RSD(div_lrck));
812+
regmap_update_bits(i2s->regmap, I2S_XFER,
813+
I2S_XFER_TXS_START | I2S_XFER_RXS_START,
814+
I2S_XFER_TXS_START | I2S_XFER_RXS_START);
815+
816+
pm_runtime_forbid(i2s->dev);
817+
818+
dev_info(i2s->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n",
819+
mclk_rate, bclk_rate, DEFAULT_FS);
820+
821+
return 0;
822+
}
823+
776824
static int rockchip_i2s_probe(struct platform_device *pdev)
777825
{
778826
struct device_node *node = pdev->dev.of_node;
@@ -781,8 +829,7 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
781829
struct snd_soc_dai_driver *soc_dai;
782830
struct resource *res;
783831
void __iomem *regs;
784-
int ret;
785-
int val;
832+
int ret, val, i;
786833

787834
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
788835
if (!i2s)
@@ -800,6 +847,10 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
800847
i2s->pins = of_id->data;
801848
}
802849

850+
for (i = 0; i < ARRAY_SIZE(of_quirks); i++)
851+
if (device_property_read_bool(i2s->dev, of_quirks[i].quirk))
852+
i2s->quirks |= of_quirks[i].id;
853+
803854
i2s->reset_m = devm_reset_control_get(&pdev->dev, "reset-m");
804855
i2s->reset_h = devm_reset_control_get(&pdev->dev, "reset-h");
805856

@@ -898,6 +949,17 @@ static int rockchip_i2s_probe(struct platform_device *pdev)
898949
regmap_update_bits(i2s->regmap, I2S_CKR,
899950
I2S_CKR_TRCM_MASK, i2s->clk_trcm);
900951

952+
/*
953+
* CLK_ALWAYS_ON should be placed after all registers write done,
954+
* because this situation will enable XFER bit which will make
955+
* some registers(depend on XFER) write failed.
956+
*/
957+
if (i2s->quirks & QUIRK_ALWAYS_ON) {
958+
ret = rockchip_i2s_keep_clk_always_on(i2s);
959+
if (ret)
960+
goto err_clk;
961+
}
962+
901963
/*
902964
* MUST: after pm_runtime_enable step, any register R/W
903965
* should be wrapped with pm_runtime_get_sync/put.

0 commit comments

Comments
 (0)