Skip to content

Commit 52ac28b

Browse files
author
Sugar Zhang
committed
ASoC: rockchip: i2s: Add support for PCM R/W Wait Time
ALSA core blocks userspace for 10 seconds for PCM R/W default. Consider the situation BT-slave which acts as SLAVE mode, when BT-master offline sometime, the CLK lost, user have to wait the core timeout(10s), it's quite bad experience. This patch allows userspace to override the WAIT_TIME to recover more quickly from terminal audio stream. especially for stream which have no mechanism to detect the LINK offline. Usage: /# amixer -c 0 contents | grep Wait numid=43,iface=PCM,name='PCM Read Wait Time MS' numid=44,iface=PCM,name='PCM Write Wait Time MS' /# amixer -c 0 cset numid=43 500 numid=43,iface=PCM,name='PCM Read Wait Time MS' ; type=INTEGER,access=rw------,values=1,min=0,max=10000,step=1 : values=500 Signed-off-by: Sugar Zhang <sugar.zhang@rock-chips.com> Change-Id: I36c03859d3d91552dc4247864fe6697624245b6c
1 parent a859bf6 commit 52ac28b

1 file changed

Lines changed: 109 additions & 0 deletions

File tree

sound/soc/rockchip/rockchip_i2s.c

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434
#define DEFAULT_MCLK_FS 256
3535
#define DEFAULT_FS 48000
3636

37+
#define WAIT_TIME_MS_MAX 10000
38+
3739
#define QUIRK_ALWAYS_ON BIT(0)
3840

3941
struct rk_i2s_pins {
@@ -56,6 +58,8 @@ struct rk_i2s_dev {
5658
struct reset_control *reset_m;
5759
struct reset_control *reset_h;
5860

61+
struct snd_pcm_substream *substreams[SNDRV_PCM_STREAM_LAST + 1];
62+
unsigned int wait_time[SNDRV_PCM_STREAM_LAST + 1];
5963
/*
6064
* Used to indicate the tx/rx status.
6165
* I2S controller hopes to start the tx and rx together,
@@ -623,7 +627,34 @@ static int rockchip_i2s_dai_probe(struct snd_soc_dai *dai)
623627
return 0;
624628
}
625629

630+
static int rockchip_i2s_startup(struct snd_pcm_substream *substream,
631+
struct snd_soc_dai *dai)
632+
{
633+
struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
634+
int stream = substream->stream;
635+
636+
if (i2s->substreams[stream])
637+
return -EBUSY;
638+
639+
if (i2s->wait_time[stream])
640+
substream->wait_time = msecs_to_jiffies(i2s->wait_time[stream]);
641+
642+
i2s->substreams[stream] = substream;
643+
644+
return 0;
645+
}
646+
647+
static void rockchip_i2s_shutdown(struct snd_pcm_substream *substream,
648+
struct snd_soc_dai *dai)
649+
{
650+
struct rk_i2s_dev *i2s = snd_soc_dai_get_drvdata(dai);
651+
652+
i2s->substreams[substream->stream] = NULL;
653+
}
654+
626655
static const struct snd_soc_dai_ops rockchip_i2s_dai_ops = {
656+
.startup = rockchip_i2s_startup,
657+
.shutdown = rockchip_i2s_shutdown,
627658
.hw_params = rockchip_i2s_hw_params,
628659
.set_sysclk = rockchip_i2s_set_sysclk,
629660
.set_fmt = rockchip_i2s_set_fmt,
@@ -659,8 +690,86 @@ static struct snd_soc_dai_driver rockchip_i2s_dai = {
659690
.ops = &rockchip_i2s_dai_ops,
660691
};
661692

693+
static int rockchip_i2s_wait_time_info(struct snd_kcontrol *kcontrol,
694+
struct snd_ctl_elem_info *uinfo)
695+
{
696+
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
697+
uinfo->count = 1;
698+
uinfo->value.integer.min = 0;
699+
uinfo->value.integer.max = WAIT_TIME_MS_MAX;
700+
uinfo->value.integer.step = 1;
701+
702+
return 0;
703+
}
704+
705+
static int rockchip_i2s_rd_wait_time_get(struct snd_kcontrol *kcontrol,
706+
struct snd_ctl_elem_value *ucontrol)
707+
{
708+
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
709+
struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component);
710+
711+
ucontrol->value.integer.value[0] = i2s->wait_time[SNDRV_PCM_STREAM_CAPTURE];
712+
713+
return 0;
714+
}
715+
716+
static int rockchip_i2s_rd_wait_time_put(struct snd_kcontrol *kcontrol,
717+
struct snd_ctl_elem_value *ucontrol)
718+
{
719+
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
720+
struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component);
721+
722+
if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
723+
return -EINVAL;
724+
725+
i2s->wait_time[SNDRV_PCM_STREAM_CAPTURE] = ucontrol->value.integer.value[0];
726+
727+
return 1;
728+
}
729+
730+
static int rockchip_i2s_wr_wait_time_get(struct snd_kcontrol *kcontrol,
731+
struct snd_ctl_elem_value *ucontrol)
732+
{
733+
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
734+
struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component);
735+
736+
ucontrol->value.integer.value[0] = i2s->wait_time[SNDRV_PCM_STREAM_PLAYBACK];
737+
738+
return 0;
739+
}
740+
741+
static int rockchip_i2s_wr_wait_time_put(struct snd_kcontrol *kcontrol,
742+
struct snd_ctl_elem_value *ucontrol)
743+
{
744+
struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol);
745+
struct rk_i2s_dev *i2s = snd_soc_component_get_drvdata(component);
746+
747+
if (ucontrol->value.integer.value[0] > WAIT_TIME_MS_MAX)
748+
return -EINVAL;
749+
750+
i2s->wait_time[SNDRV_PCM_STREAM_PLAYBACK] = ucontrol->value.integer.value[0];
751+
752+
return 1;
753+
}
754+
755+
#define SAI_PCM_WAIT_TIME(xname, xhandler_get, xhandler_put) \
756+
{ .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = xname, \
757+
.info = rockchip_i2s_wait_time_info, \
758+
.get = xhandler_get, .put = xhandler_put }
759+
760+
static const struct snd_kcontrol_new rockchip_i2s_snd_controls[] = {
761+
SAI_PCM_WAIT_TIME("PCM Read Wait Time MS",
762+
rockchip_i2s_rd_wait_time_get,
763+
rockchip_i2s_rd_wait_time_put),
764+
SAI_PCM_WAIT_TIME("PCM Write Wait Time MS",
765+
rockchip_i2s_wr_wait_time_get,
766+
rockchip_i2s_wr_wait_time_put),
767+
};
768+
662769
static const struct snd_soc_component_driver rockchip_i2s_component = {
663770
.name = DRV_NAME,
771+
.controls = rockchip_i2s_snd_controls,
772+
.num_controls = ARRAY_SIZE(rockchip_i2s_snd_controls),
664773
};
665774

666775
static bool rockchip_i2s_wr_reg(struct device *dev, unsigned int reg)

0 commit comments

Comments
 (0)