Merge remote-tracking branch 'asoc/topic/rcar' into asoc-next
This commit is contained in:
commit
078b3a0205
|
@ -4,7 +4,7 @@ Renesas R-Car sound
|
||||||
* Modules
|
* Modules
|
||||||
=============================================
|
=============================================
|
||||||
|
|
||||||
Renesas R-Car sound is constructed from below modules
|
Renesas R-Car and RZ/G sound is constructed from below modules
|
||||||
(for Gen2 or later)
|
(for Gen2 or later)
|
||||||
|
|
||||||
SCU : Sampling Rate Converter Unit
|
SCU : Sampling Rate Converter Unit
|
||||||
|
@ -197,12 +197,17 @@ Ex)
|
||||||
[MEM] -> [SRC2] -> [CTU03] -+
|
[MEM] -> [SRC2] -> [CTU03] -+
|
||||||
|
|
||||||
sound {
|
sound {
|
||||||
|
#address-cells = <1>;
|
||||||
|
#size-cells = <0>;
|
||||||
|
|
||||||
compatible = "simple-scu-audio-card";
|
compatible = "simple-scu-audio-card";
|
||||||
...
|
...
|
||||||
simple-audio-card,cpu-0 {
|
simple-audio-card,cpu@0 {
|
||||||
|
reg = <0>;
|
||||||
sound-dai = <&rcar_sound 0>;
|
sound-dai = <&rcar_sound 0>;
|
||||||
};
|
};
|
||||||
simple-audio-card,cpu-1 {
|
simple-audio-card,cpu@1 {
|
||||||
|
reg = <1>;
|
||||||
sound-dai = <&rcar_sound 1>;
|
sound-dai = <&rcar_sound 1>;
|
||||||
};
|
};
|
||||||
simple-audio-card,codec {
|
simple-audio-card,codec {
|
||||||
|
@ -334,9 +339,11 @@ Required properties:
|
||||||
|
|
||||||
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
- compatible : "renesas,rcar_sound-<soctype>", fallbacks
|
||||||
"renesas,rcar_sound-gen1" if generation1, and
|
"renesas,rcar_sound-gen1" if generation1, and
|
||||||
"renesas,rcar_sound-gen2" if generation2
|
"renesas,rcar_sound-gen2" if generation2 (or RZ/G1)
|
||||||
"renesas,rcar_sound-gen3" if generation3
|
"renesas,rcar_sound-gen3" if generation3
|
||||||
Examples with soctypes are:
|
Examples with soctypes are:
|
||||||
|
- "renesas,rcar_sound-r8a7743" (RZ/G1M)
|
||||||
|
- "renesas,rcar_sound-r8a7745" (RZ/G1E)
|
||||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||||
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
- "renesas,rcar_sound-r8a7779" (R-Car H1)
|
||||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||||
|
|
|
@ -494,6 +494,8 @@ int soc_new_pcm(struct snd_soc_pcm_runtime *rtd, int num);
|
||||||
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
|
int snd_soc_new_compress(struct snd_soc_pcm_runtime *rtd, int num);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void snd_soc_disconnect_sync(struct device *dev);
|
||||||
|
|
||||||
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
|
struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card,
|
||||||
const char *dai_link, int stream);
|
const char *dai_link, int stream);
|
||||||
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
|
struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
|
||||||
|
|
|
@ -206,7 +206,8 @@ static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
snd_jack_set_key(rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_MEDIA);
|
snd_jack_set_key(
|
||||||
|
rockchip_sound_jack.jack, SND_JACK_BTN_0, KEY_PLAYPAUSE);
|
||||||
snd_jack_set_key(
|
snd_jack_set_key(
|
||||||
rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
|
rockchip_sound_jack.jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
|
||||||
snd_jack_set_key(
|
snd_jack_set_key(
|
||||||
|
|
|
@ -197,16 +197,27 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
|
int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* params will be added when refine
|
||||||
|
* see
|
||||||
|
* __rsnd_soc_hw_rule_rate()
|
||||||
|
* __rsnd_soc_hw_rule_channels()
|
||||||
|
*/
|
||||||
|
if (params)
|
||||||
|
return params_channels(params);
|
||||||
|
else
|
||||||
return runtime->channels;
|
return runtime->channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
|
int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
int chan = rsnd_runtime_channel_original(io);
|
int chan = rsnd_runtime_channel_original_with_params(io, params);
|
||||||
struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
|
struct rsnd_mod *ctu_mod = rsnd_io_to_mod_ctu(io);
|
||||||
|
|
||||||
if (ctu_mod) {
|
if (ctu_mod) {
|
||||||
|
@ -219,12 +230,13 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
|
||||||
return chan;
|
return chan;
|
||||||
}
|
}
|
||||||
|
|
||||||
int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
|
int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
|
||||||
|
struct snd_pcm_hw_params *params)
|
||||||
{
|
{
|
||||||
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
|
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
|
||||||
int chan = rsnd_io_is_play(io) ?
|
int chan = rsnd_io_is_play(io) ?
|
||||||
rsnd_runtime_channel_after_ctu(io) :
|
rsnd_runtime_channel_after_ctu_with_params(io, params) :
|
||||||
rsnd_runtime_channel_original(io);
|
rsnd_runtime_channel_original_with_params(io, params);
|
||||||
|
|
||||||
/* Use Multi SSI */
|
/* Use Multi SSI */
|
||||||
if (rsnd_runtime_is_ssi_multi(io))
|
if (rsnd_runtime_is_ssi_multi(io))
|
||||||
|
@ -262,10 +274,10 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||||
struct device *dev = rsnd_priv_to_dev(priv);
|
struct device *dev = rsnd_priv_to_dev(priv);
|
||||||
|
|
||||||
switch (runtime->sample_bits) {
|
switch (snd_pcm_format_width(runtime->format)) {
|
||||||
case 16:
|
case 16:
|
||||||
return 8 << 16;
|
return 8 << 16;
|
||||||
case 32:
|
case 24:
|
||||||
return 0 << 16;
|
return 0 << 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,11 +294,12 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||||
struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
|
struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io);
|
||||||
struct rsnd_mod *target;
|
struct rsnd_mod *target;
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||||
u32 val = 0x76543210;
|
|
||||||
u32 mask = ~0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* *Hardware* L/R and *Software* L/R are inverted.
|
* *Hardware* L/R and *Software* L/R are inverted for 16bit data.
|
||||||
|
* 31..16 15...0
|
||||||
|
* HW: [L ch] [R ch]
|
||||||
|
* SW: [R ch] [L ch]
|
||||||
* We need to care about inversion timing to control
|
* We need to care about inversion timing to control
|
||||||
* Playback/Capture correctly.
|
* Playback/Capture correctly.
|
||||||
* The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
|
* The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
|
||||||
|
@ -313,27 +326,13 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
|
||||||
target = cmd ? cmd : ssiu;
|
target = cmd ? cmd : ssiu;
|
||||||
}
|
}
|
||||||
|
|
||||||
mask <<= runtime->channels * 4;
|
/* Non target mod or 24bit data needs normal DALIGN */
|
||||||
val = val & mask;
|
if ((snd_pcm_format_width(runtime->format) != 16) ||
|
||||||
|
(mod != target))
|
||||||
switch (runtime->sample_bits) {
|
|
||||||
case 16:
|
|
||||||
val |= 0x67452301 & ~mask;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
val |= 0x76543210 & ~mask;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* exchange channeles on SRC if possible,
|
|
||||||
* otherwise, R/L volume settings on DVC
|
|
||||||
* changes inverted channels
|
|
||||||
*/
|
|
||||||
if (mod == target)
|
|
||||||
return val;
|
|
||||||
else
|
|
||||||
return 0x76543210;
|
return 0x76543210;
|
||||||
|
/* Target mod needs inverted DALIGN when 16bit */
|
||||||
|
else
|
||||||
|
return 0x67452301;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
|
u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
|
||||||
|
@ -363,12 +362,8 @@ u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
|
||||||
* HW 24bit data is located as 0x******00
|
* HW 24bit data is located as 0x******00
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
switch (runtime->sample_bits) {
|
if (snd_pcm_format_width(runtime->format) == 16)
|
||||||
case 16:
|
|
||||||
return 0;
|
return 0;
|
||||||
case 32:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
|
for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
|
||||||
tmod = rsnd_io_to_mod(io, mods[i]);
|
tmod = rsnd_io_to_mod(io, mods[i]);
|
||||||
|
@ -616,8 +611,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case SNDRV_PCM_TRIGGER_START:
|
case SNDRV_PCM_TRIGGER_START:
|
||||||
case SNDRV_PCM_TRIGGER_RESUME:
|
case SNDRV_PCM_TRIGGER_RESUME:
|
||||||
rsnd_dai_stream_init(io, substream);
|
|
||||||
|
|
||||||
ret = rsnd_dai_call(init, io, priv);
|
ret = rsnd_dai_call(init, io, priv);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
goto dai_trigger_end;
|
goto dai_trigger_end;
|
||||||
|
@ -639,7 +632,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
|
||||||
|
|
||||||
ret |= rsnd_dai_call(quit, io, priv);
|
ret |= rsnd_dai_call(quit, io, priv);
|
||||||
|
|
||||||
rsnd_dai_stream_quit(io);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
|
@ -784,8 +776,9 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
|
||||||
return snd_interval_refine(iv, &p);
|
return snd_interval_refine(iv, &p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
|
static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||||
struct snd_pcm_hw_rule *rule)
|
struct snd_pcm_hw_rule *rule,
|
||||||
|
int is_play)
|
||||||
{
|
{
|
||||||
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||||
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||||
|
@ -793,25 +786,37 @@ static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
|
||||||
struct snd_soc_dai *dai = rule->private;
|
struct snd_soc_dai *dai = rule->private;
|
||||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||||
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
|
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
|
||||||
|
struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* possible sampling rate limitation is same as
|
* possible sampling rate limitation is same as
|
||||||
* 2ch if it supports multi ssi
|
* 2ch if it supports multi ssi
|
||||||
|
* and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
|
||||||
*/
|
*/
|
||||||
ic = *ic_;
|
ic = *ic_;
|
||||||
if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
|
ic.min =
|
||||||
ic.min = 2;
|
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
|
||||||
ic.max = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
|
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
|
||||||
ARRAY_SIZE(rsnd_soc_hw_rate_list),
|
ARRAY_SIZE(rsnd_soc_hw_rate_list),
|
||||||
&ic, ir);
|
&ic, ir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rsnd_soc_hw_rule_rate_playback(struct snd_pcm_hw_params *params,
|
||||||
static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
|
|
||||||
struct snd_pcm_hw_rule *rule)
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
return __rsnd_soc_hw_rule_rate(params, rule, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsnd_soc_hw_rule_rate_capture(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
return __rsnd_soc_hw_rule_rate(params, rule, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule,
|
||||||
|
int is_play)
|
||||||
{
|
{
|
||||||
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
struct snd_interval *ic_ = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||||
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
struct snd_interval *ir = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||||
|
@ -819,22 +824,34 @@ static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
|
||||||
struct snd_soc_dai *dai = rule->private;
|
struct snd_soc_dai *dai = rule->private;
|
||||||
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
|
||||||
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
|
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
|
||||||
|
struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* possible sampling rate limitation is same as
|
* possible sampling rate limitation is same as
|
||||||
* 2ch if it supports multi ssi
|
* 2ch if it supports multi ssi
|
||||||
|
* and same as 8ch if TDM 6ch (see rsnd_ssi_config_init())
|
||||||
*/
|
*/
|
||||||
ic = *ic_;
|
ic = *ic_;
|
||||||
if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
|
ic.min =
|
||||||
ic.min = 2;
|
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
|
||||||
ic.max = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
|
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
|
||||||
ARRAY_SIZE(rsnd_soc_hw_channels_list),
|
ARRAY_SIZE(rsnd_soc_hw_channels_list),
|
||||||
ir, &ic);
|
ir, &ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rsnd_soc_hw_rule_channels_playback(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
return __rsnd_soc_hw_rule_channels(params, rule, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsnd_soc_hw_rule_channels_capture(struct snd_pcm_hw_params *params,
|
||||||
|
struct snd_pcm_hw_rule *rule)
|
||||||
|
{
|
||||||
|
return __rsnd_soc_hw_rule_channels(params, rule, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
|
static const struct snd_pcm_hardware rsnd_pcm_hardware = {
|
||||||
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
.info = SNDRV_PCM_INFO_INTERLEAVED |
|
||||||
SNDRV_PCM_INFO_MMAP |
|
SNDRV_PCM_INFO_MMAP |
|
||||||
|
@ -859,6 +876,8 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
|
||||||
int ret;
|
int ret;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
rsnd_dai_stream_init(io, substream);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Channel Limitation
|
* Channel Limitation
|
||||||
* It depends on Platform design
|
* It depends on Platform design
|
||||||
|
@ -886,11 +905,17 @@ static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
|
||||||
* It depends on Clock Master Mode
|
* It depends on Clock Master Mode
|
||||||
*/
|
*/
|
||||||
if (rsnd_rdai_is_clk_master(rdai)) {
|
if (rsnd_rdai_is_clk_master(rdai)) {
|
||||||
|
int is_play = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
|
||||||
|
|
||||||
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||||
rsnd_soc_hw_rule_rate, dai,
|
is_play ? rsnd_soc_hw_rule_rate_playback :
|
||||||
|
rsnd_soc_hw_rule_rate_capture,
|
||||||
|
dai,
|
||||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||||
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||||
rsnd_soc_hw_rule_channels, dai,
|
is_play ? rsnd_soc_hw_rule_channels_playback :
|
||||||
|
rsnd_soc_hw_rule_channels_capture,
|
||||||
|
dai,
|
||||||
SNDRV_PCM_HW_PARAM_RATE, -1);
|
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -915,6 +940,8 @@ static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
|
||||||
* call rsnd_dai_call without spinlock
|
* call rsnd_dai_call without spinlock
|
||||||
*/
|
*/
|
||||||
rsnd_dai_call(nolock_stop, io, priv);
|
rsnd_dai_call(nolock_stop, io, priv);
|
||||||
|
|
||||||
|
rsnd_dai_stream_quit(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
|
static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
|
||||||
|
@ -990,7 +1017,7 @@ of_node_compatible:
|
||||||
|
|
||||||
static void __rsnd_dai_probe(struct rsnd_priv *priv,
|
static void __rsnd_dai_probe(struct rsnd_priv *priv,
|
||||||
struct device_node *dai_np,
|
struct device_node *dai_np,
|
||||||
int dai_i, int is_graph)
|
int dai_i)
|
||||||
{
|
{
|
||||||
struct device_node *playback, *capture;
|
struct device_node *playback, *capture;
|
||||||
struct rsnd_dai_stream *io_playback;
|
struct rsnd_dai_stream *io_playback;
|
||||||
|
@ -1089,13 +1116,13 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
|
||||||
dai_i = 0;
|
dai_i = 0;
|
||||||
if (is_graph) {
|
if (is_graph) {
|
||||||
for_each_endpoint_of_node(dai_node, dai_np) {
|
for_each_endpoint_of_node(dai_node, dai_np) {
|
||||||
__rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
|
__rsnd_dai_probe(priv, dai_np, dai_i);
|
||||||
rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
|
rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
|
||||||
dai_i++;
|
dai_i++;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for_each_child_of_node(dai_node, dai_np)
|
for_each_child_of_node(dai_node, dai_np)
|
||||||
__rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
|
__rsnd_dai_probe(priv, dai_np, dai_i++);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1496,6 +1523,8 @@ static int rsnd_remove(struct platform_device *pdev)
|
||||||
};
|
};
|
||||||
int ret = 0, i;
|
int ret = 0, i;
|
||||||
|
|
||||||
|
snd_soc_disconnect_sync(&pdev->dev);
|
||||||
|
|
||||||
pm_runtime_disable(&pdev->dev);
|
pm_runtime_disable(&pdev->dev);
|
||||||
|
|
||||||
for_each_rsnd_dai(rdai, priv, i) {
|
for_each_rsnd_dai(rdai, priv, i) {
|
||||||
|
|
|
@ -71,25 +71,7 @@ static struct rsnd_mod mem = {
|
||||||
static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
|
static void __rsnd_dmaen_complete(struct rsnd_mod *mod,
|
||||||
struct rsnd_dai_stream *io)
|
struct rsnd_dai_stream *io)
|
||||||
{
|
{
|
||||||
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
|
|
||||||
bool elapsed = false;
|
|
||||||
unsigned long flags;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Renesas sound Gen1 needs 1 DMAC,
|
|
||||||
* Gen2 needs 2 DMAC.
|
|
||||||
* In Gen2 case, it are Audio-DMAC, and Audio-DMAC-peri-peri.
|
|
||||||
* But, Audio-DMAC-peri-peri doesn't have interrupt,
|
|
||||||
* and this driver is assuming that here.
|
|
||||||
*/
|
|
||||||
spin_lock_irqsave(&priv->lock, flags);
|
|
||||||
|
|
||||||
if (rsnd_io_is_working(io))
|
if (rsnd_io_is_working(io))
|
||||||
elapsed = true;
|
|
||||||
|
|
||||||
spin_unlock_irqrestore(&priv->lock, flags);
|
|
||||||
|
|
||||||
if (elapsed)
|
|
||||||
rsnd_dai_period_elapsed(io);
|
rsnd_dai_period_elapsed(io);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -399,9 +399,18 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
|
||||||
struct device_node *playback,
|
struct device_node *playback,
|
||||||
struct device_node *capture);
|
struct device_node *capture);
|
||||||
|
|
||||||
int rsnd_runtime_channel_original(struct rsnd_dai_stream *io);
|
#define rsnd_runtime_channel_original(io) \
|
||||||
int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io);
|
rsnd_runtime_channel_original_with_params(io, NULL)
|
||||||
int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io);
|
int rsnd_runtime_channel_original_with_params(struct rsnd_dai_stream *io,
|
||||||
|
struct snd_pcm_hw_params *params);
|
||||||
|
#define rsnd_runtime_channel_after_ctu(io) \
|
||||||
|
rsnd_runtime_channel_after_ctu_with_params(io, NULL)
|
||||||
|
int rsnd_runtime_channel_after_ctu_with_params(struct rsnd_dai_stream *io,
|
||||||
|
struct snd_pcm_hw_params *params);
|
||||||
|
#define rsnd_runtime_channel_for_ssi(io) \
|
||||||
|
rsnd_runtime_channel_for_ssi_with_params(io, NULL)
|
||||||
|
int rsnd_runtime_channel_for_ssi_with_params(struct rsnd_dai_stream *io,
|
||||||
|
struct snd_pcm_hw_params *params);
|
||||||
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
|
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io);
|
||||||
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
|
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io);
|
||||||
|
|
||||||
|
|
|
@ -79,8 +79,8 @@ struct rsnd_ssi {
|
||||||
int irq;
|
int irq;
|
||||||
unsigned int usrcnt;
|
unsigned int usrcnt;
|
||||||
|
|
||||||
|
/* for PIO */
|
||||||
int byte_pos;
|
int byte_pos;
|
||||||
int period_pos;
|
|
||||||
int byte_per_period;
|
int byte_per_period;
|
||||||
int next_period_byte;
|
int next_period_byte;
|
||||||
};
|
};
|
||||||
|
@ -371,11 +371,11 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
|
||||||
if (rsnd_io_is_play(io))
|
if (rsnd_io_is_play(io))
|
||||||
cr_own |= TRMD;
|
cr_own |= TRMD;
|
||||||
|
|
||||||
switch (runtime->sample_bits) {
|
switch (snd_pcm_format_width(runtime->format)) {
|
||||||
case 16:
|
case 16:
|
||||||
cr_own |= DWL_16;
|
cr_own |= DWL_16;
|
||||||
break;
|
break;
|
||||||
case 32:
|
case 24:
|
||||||
cr_own |= DWL_24;
|
cr_own |= DWL_24;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -414,63 +414,6 @@ static void rsnd_ssi_register_setup(struct rsnd_mod *mod)
|
||||||
ssi->cr_en);
|
ssi->cr_en);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rsnd_ssi_pointer_init(struct rsnd_mod *mod,
|
|
||||||
struct rsnd_dai_stream *io)
|
|
||||||
{
|
|
||||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
|
||||||
|
|
||||||
ssi->byte_pos = 0;
|
|
||||||
ssi->period_pos = 0;
|
|
||||||
ssi->byte_per_period = runtime->period_size *
|
|
||||||
runtime->channels *
|
|
||||||
samples_to_bytes(runtime, 1);
|
|
||||||
ssi->next_period_byte = ssi->byte_per_period;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rsnd_ssi_pointer_offset(struct rsnd_mod *mod,
|
|
||||||
struct rsnd_dai_stream *io,
|
|
||||||
int additional)
|
|
||||||
{
|
|
||||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
|
||||||
int pos = ssi->byte_pos + additional;
|
|
||||||
|
|
||||||
pos %= (runtime->periods * ssi->byte_per_period);
|
|
||||||
|
|
||||||
return pos;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool rsnd_ssi_pointer_update(struct rsnd_mod *mod,
|
|
||||||
struct rsnd_dai_stream *io,
|
|
||||||
int byte)
|
|
||||||
{
|
|
||||||
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
|
||||||
bool ret = false;
|
|
||||||
int byte_pos;
|
|
||||||
|
|
||||||
byte_pos = ssi->byte_pos + byte;
|
|
||||||
|
|
||||||
if (byte_pos >= ssi->next_period_byte) {
|
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
|
||||||
|
|
||||||
ssi->period_pos++;
|
|
||||||
ssi->next_period_byte += ssi->byte_per_period;
|
|
||||||
|
|
||||||
if (ssi->period_pos >= runtime->periods) {
|
|
||||||
byte_pos = 0;
|
|
||||||
ssi->period_pos = 0;
|
|
||||||
ssi->next_period_byte = ssi->byte_per_period;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
WRITE_ONCE(ssi->byte_pos, byte_pos);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SSI mod common functions
|
* SSI mod common functions
|
||||||
*/
|
*/
|
||||||
|
@ -484,8 +427,6 @@ static int rsnd_ssi_init(struct rsnd_mod *mod,
|
||||||
if (!rsnd_ssi_is_run_mods(mod, io))
|
if (!rsnd_ssi_is_run_mods(mod, io))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
rsnd_ssi_pointer_init(mod, io);
|
|
||||||
|
|
||||||
ssi->usrcnt++;
|
ssi->usrcnt++;
|
||||||
|
|
||||||
rsnd_mod_power_on(mod);
|
rsnd_mod_power_on(mod);
|
||||||
|
@ -656,6 +597,8 @@ static int rsnd_ssi_irq(struct rsnd_mod *mod,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
|
||||||
|
struct rsnd_dai_stream *io);
|
||||||
static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
|
static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
|
||||||
struct rsnd_dai_stream *io)
|
struct rsnd_dai_stream *io)
|
||||||
{
|
{
|
||||||
|
@ -674,30 +617,8 @@ static void __rsnd_ssi_interrupt(struct rsnd_mod *mod,
|
||||||
status = rsnd_ssi_status_get(mod);
|
status = rsnd_ssi_status_get(mod);
|
||||||
|
|
||||||
/* PIO only */
|
/* PIO only */
|
||||||
if (!is_dma && (status & DIRQ)) {
|
if (!is_dma && (status & DIRQ))
|
||||||
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
elapsed = rsnd_ssi_pio_interrupt(mod, io);
|
||||||
u32 *buf = (u32 *)(runtime->dma_area +
|
|
||||||
rsnd_ssi_pointer_offset(mod, io, 0));
|
|
||||||
int shift = 0;
|
|
||||||
|
|
||||||
switch (runtime->sample_bits) {
|
|
||||||
case 32:
|
|
||||||
shift = 8;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 8/16/32 data can be assesse to TDR/RDR register
|
|
||||||
* directly as 32bit data
|
|
||||||
* see rsnd_ssi_init()
|
|
||||||
*/
|
|
||||||
if (rsnd_io_is_play(io))
|
|
||||||
rsnd_mod_write(mod, SSITDR, (*buf) << shift);
|
|
||||||
else
|
|
||||||
*buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
|
|
||||||
|
|
||||||
elapsed = rsnd_ssi_pointer_update(mod, io, sizeof(*buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* DMA only */
|
/* DMA only */
|
||||||
if (is_dma && (status & (UIRQ | OIRQ)))
|
if (is_dma && (status & (UIRQ | OIRQ)))
|
||||||
|
@ -835,7 +756,71 @@ static int rsnd_ssi_common_remove(struct rsnd_mod *mod,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rsnd_ssi_pointer(struct rsnd_mod *mod,
|
/*
|
||||||
|
* SSI PIO functions
|
||||||
|
*/
|
||||||
|
static bool rsnd_ssi_pio_interrupt(struct rsnd_mod *mod,
|
||||||
|
struct rsnd_dai_stream *io)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||||
|
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
||||||
|
u32 *buf = (u32 *)(runtime->dma_area + ssi->byte_pos);
|
||||||
|
int shift = 0;
|
||||||
|
int byte_pos;
|
||||||
|
bool elapsed = false;
|
||||||
|
|
||||||
|
if (snd_pcm_format_width(runtime->format) == 24)
|
||||||
|
shift = 8;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 8/16/32 data can be assesse to TDR/RDR register
|
||||||
|
* directly as 32bit data
|
||||||
|
* see rsnd_ssi_init()
|
||||||
|
*/
|
||||||
|
if (rsnd_io_is_play(io))
|
||||||
|
rsnd_mod_write(mod, SSITDR, (*buf) << shift);
|
||||||
|
else
|
||||||
|
*buf = (rsnd_mod_read(mod, SSIRDR) >> shift);
|
||||||
|
|
||||||
|
byte_pos = ssi->byte_pos + sizeof(*buf);
|
||||||
|
|
||||||
|
if (byte_pos >= ssi->next_period_byte) {
|
||||||
|
int period_pos = byte_pos / ssi->byte_per_period;
|
||||||
|
|
||||||
|
if (period_pos >= runtime->periods) {
|
||||||
|
byte_pos = 0;
|
||||||
|
period_pos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssi->next_period_byte = (period_pos + 1) * ssi->byte_per_period;
|
||||||
|
|
||||||
|
elapsed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_ONCE(ssi->byte_pos, byte_pos);
|
||||||
|
|
||||||
|
return elapsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsnd_ssi_pio_init(struct rsnd_mod *mod,
|
||||||
|
struct rsnd_dai_stream *io,
|
||||||
|
struct rsnd_priv *priv)
|
||||||
|
{
|
||||||
|
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
|
||||||
|
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
|
||||||
|
|
||||||
|
if (!rsnd_ssi_is_parent(mod, io)) {
|
||||||
|
ssi->byte_pos = 0;
|
||||||
|
ssi->byte_per_period = runtime->period_size *
|
||||||
|
runtime->channels *
|
||||||
|
samples_to_bytes(runtime, 1);
|
||||||
|
ssi->next_period_byte = ssi->byte_per_period;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rsnd_ssi_init(mod, io, priv);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rsnd_ssi_pio_pointer(struct rsnd_mod *mod,
|
||||||
struct rsnd_dai_stream *io,
|
struct rsnd_dai_stream *io,
|
||||||
snd_pcm_uframes_t *pointer)
|
snd_pcm_uframes_t *pointer)
|
||||||
{
|
{
|
||||||
|
@ -851,12 +836,12 @@ static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
|
||||||
.name = SSI_NAME,
|
.name = SSI_NAME,
|
||||||
.probe = rsnd_ssi_common_probe,
|
.probe = rsnd_ssi_common_probe,
|
||||||
.remove = rsnd_ssi_common_remove,
|
.remove = rsnd_ssi_common_remove,
|
||||||
.init = rsnd_ssi_init,
|
.init = rsnd_ssi_pio_init,
|
||||||
.quit = rsnd_ssi_quit,
|
.quit = rsnd_ssi_quit,
|
||||||
.start = rsnd_ssi_start,
|
.start = rsnd_ssi_start,
|
||||||
.stop = rsnd_ssi_stop,
|
.stop = rsnd_ssi_stop,
|
||||||
.irq = rsnd_ssi_irq,
|
.irq = rsnd_ssi_irq,
|
||||||
.pointer= rsnd_ssi_pointer,
|
.pointer = rsnd_ssi_pio_pointer,
|
||||||
.pcm_new = rsnd_ssi_pcm_new,
|
.pcm_new = rsnd_ssi_pcm_new,
|
||||||
.hw_params = rsnd_ssi_hw_params,
|
.hw_params = rsnd_ssi_hw_params,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1393,6 +1393,16 @@ static int soc_init_dai_link(struct snd_soc_card *card,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void snd_soc_disconnect_sync(struct device *dev)
|
||||||
|
{
|
||||||
|
struct snd_soc_component *component = snd_soc_lookup_component(dev, NULL);
|
||||||
|
|
||||||
|
if (!component || !component->card)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snd_card_disconnect_sync(component->card->snd_card);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* snd_soc_add_dai_link - Add a DAI link dynamically
|
* snd_soc_add_dai_link - Add a DAI link dynamically
|
||||||
* @card: The ASoC card to which the DAI link is added
|
* @card: The ASoC card to which the DAI link is added
|
||||||
|
|
Loading…
Reference in New Issue