Commit fb2815f4 authored by Dragos Tarcatu's avatar Dragos Tarcatu Committed by Mark Brown

ASoC: rsnd: add support for 16/24 bit slot widths

The slot width (system word length) was fixed at 32 bits.
This patch allows also setting it to 16 or 24 bits.
Signed-off-by: default avatarDragos Tarcatu <dragos_tarcatu@mentor.com>
Signed-off-by: default avatarJiada Wang <jiada_wang@mentor.com>
Signed-off-by: default avatarTimo Wischer <twischer@de.adit-jv.com>
[Kuninori: tidyup for upstream]
Signed-off-by: default avatarKuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: default avatarHiroyuki Yokoyama <hiroyuki.yokoyama.vx@renesas.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent b5c08868
...@@ -540,6 +540,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, ...@@ -540,6 +540,14 @@ int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
return rdai->ssi_lane; return rdai->ssi_lane;
} }
int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width)
{
if (width > 0)
rdai->chan_width = width;
return rdai->chan_width;
}
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id) struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
{ {
if ((id < 0) || (id >= rsnd_rdai_nr(priv))) if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
...@@ -720,6 +728,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -720,6 +728,16 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai); struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct device *dev = rsnd_priv_to_dev(priv); struct device *dev = rsnd_priv_to_dev(priv);
switch (slot_width) {
case 16:
case 24:
case 32:
break;
default:
dev_err(dev, "unsupported slot width value: %d\n", slot_width);
return -EINVAL;
}
switch (slots) { switch (slots) {
case 2: case 2:
case 6: case 6:
...@@ -727,6 +745,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, ...@@ -727,6 +745,7 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
/* TDM Extend Mode */ /* TDM Extend Mode */
rsnd_rdai_channels_set(rdai, slots); rsnd_rdai_channels_set(rdai, slots);
rsnd_rdai_ssi_lane_set(rdai, 1); rsnd_rdai_ssi_lane_set(rdai, 1);
rsnd_rdai_width_set(rdai, slot_width);
break; break;
default: default:
dev_err(dev, "unsupported TDM slots (%d)\n", slots); dev_err(dev, "unsupported TDM slots (%d)\n", slots);
...@@ -755,7 +774,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = { ...@@ -755,7 +774,7 @@ static unsigned int rsnd_soc_hw_rate_list[] = {
192000, 192000,
}; };
static int rsnd_soc_hw_rule(struct rsnd_priv *priv, static int rsnd_soc_hw_rule(struct rsnd_dai *rdai,
unsigned int *list, int list_num, unsigned int *list, int list_num,
struct snd_interval *baseline, struct snd_interval *iv) struct snd_interval *baseline, struct snd_interval *iv)
{ {
...@@ -772,14 +791,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv, ...@@ -772,14 +791,14 @@ static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
if (!snd_interval_test(iv, list[i])) if (!snd_interval_test(iv, list[i]))
continue; continue;
rate = rsnd_ssi_clk_query(priv, rate = rsnd_ssi_clk_query(rdai,
baseline->min, list[i], NULL); baseline->min, list[i], NULL);
if (rate > 0) { if (rate > 0) {
p.min = min(p.min, list[i]); p.min = min(p.min, list[i]);
p.max = max(p.max, list[i]); p.max = max(p.max, list[i]);
} }
rate = rsnd_ssi_clk_query(priv, rate = rsnd_ssi_clk_query(rdai,
baseline->max, list[i], NULL); baseline->max, list[i], NULL);
if (rate > 0) { if (rate > 0) {
p.min = min(p.min, list[i]); p.min = min(p.min, list[i]);
...@@ -799,7 +818,6 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, ...@@ -799,7 +818,6 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
struct snd_interval ic; struct snd_interval ic;
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_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
/* /*
...@@ -811,7 +829,7 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params, ...@@ -811,7 +829,7 @@ static int __rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
ic.min = ic.min =
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list, return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_rate_list,
ARRAY_SIZE(rsnd_soc_hw_rate_list), ARRAY_SIZE(rsnd_soc_hw_rate_list),
&ic, ir); &ic, ir);
} }
...@@ -837,7 +855,6 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ...@@ -837,7 +855,6 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
struct snd_interval ic; struct snd_interval ic;
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_dai_stream *io = is_play ? &rdai->playback : &rdai->capture; struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
/* /*
...@@ -849,7 +866,7 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params, ...@@ -849,7 +866,7 @@ static int __rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
ic.min = ic.min =
ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params); ic.max = rsnd_runtime_channel_for_ssi_with_params(io, params);
return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list, return rsnd_soc_hw_rule(rdai, rsnd_soc_hw_channels_list,
ARRAY_SIZE(rsnd_soc_hw_channels_list), ARRAY_SIZE(rsnd_soc_hw_channels_list),
ir, &ic); ir, &ic);
} }
...@@ -1072,6 +1089,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv, ...@@ -1072,6 +1089,7 @@ static void __rsnd_dai_probe(struct rsnd_priv *priv,
rdai->capture.rdai = rdai; rdai->capture.rdai = rdai;
rsnd_rdai_channels_set(rdai, 2); /* default 2ch */ rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */ rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
rsnd_rdai_width_set(rdai, 32); /* default 32bit width */
for (io_i = 0;; io_i++) { for (io_i = 0;; io_i++) {
playback = of_parse_phandle(dai_np, "playback", io_i); playback = of_parse_phandle(dai_np, "playback", io_i);
......
...@@ -460,6 +460,7 @@ struct rsnd_dai { ...@@ -460,6 +460,7 @@ struct rsnd_dai {
int max_channels; /* 2ch - 16ch */ int max_channels; /* 2ch - 16ch */
int ssi_lane; /* 1lane - 4lane */ int ssi_lane; /* 1lane - 4lane */
int chan_width; /* 16/24/32 bit width */
unsigned int clk_master:1; unsigned int clk_master:1;
unsigned int bit_clk_inv:1; unsigned int bit_clk_inv:1;
...@@ -493,6 +494,11 @@ int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai, ...@@ -493,6 +494,11 @@ int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai, int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
int ssi_lane); int ssi_lane);
#define rsnd_rdai_width_set(rdai, width) \
rsnd_rdai_width_ctrl(rdai, width)
#define rsnd_rdai_width_get(rdai) \
rsnd_rdai_width_ctrl(rdai, 0)
int rsnd_rdai_width_ctrl(struct rsnd_dai *rdai, int width);
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io); void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io);
int rsnd_dai_connect(struct rsnd_mod *mod, int rsnd_dai_connect(struct rsnd_mod *mod,
struct rsnd_dai_stream *io, struct rsnd_dai_stream *io,
...@@ -702,7 +708,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod); ...@@ -702,7 +708,7 @@ int __rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
void rsnd_parse_connect_ssi(struct rsnd_dai *rdai, void rsnd_parse_connect_ssi(struct rsnd_dai *rdai,
struct device_node *playback, struct device_node *playback,
struct device_node *capture); struct device_node *capture);
unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
int param1, int param2, int *idx); int param1, int param2, int *idx);
/* /*
......
...@@ -42,7 +42,13 @@ ...@@ -42,7 +42,13 @@
#define DWL_24 (5 << 19) /* Data Word Length */ #define DWL_24 (5 << 19) /* Data Word Length */
#define DWL_32 (6 << 19) /* Data Word Length */ #define DWL_32 (6 << 19) /* Data Word Length */
/*
* System word length
*/
#define SWL_16 (1 << 16) /* R/W System Word Length */
#define SWL_24 (2 << 16) /* R/W System Word Length */
#define SWL_32 (3 << 16) /* R/W System Word Length */ #define SWL_32 (3 << 16) /* R/W System Word Length */
#define SCKD (1 << 15) /* Serial Bit Clock Direction */ #define SCKD (1 << 15) /* Serial Bit Clock Direction */
#define SWSD (1 << 14) /* Serial WS Direction */ #define SWSD (1 << 14) /* Serial WS Direction */
#define SCKP (1 << 13) /* Serial Bit Clock Polarity */ #define SCKP (1 << 13) /* Serial Bit Clock Polarity */
...@@ -220,14 +226,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io) ...@@ -220,14 +226,32 @@ u32 rsnd_ssi_multi_slaves_runtime(struct rsnd_dai_stream *io)
return 0; return 0;
} }
unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, static u32 rsnd_rdai_width_to_swl(struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct device *dev = rsnd_priv_to_dev(priv);
int width = rsnd_rdai_width_get(rdai);
switch (width) {
case 32: return SWL_32;
case 24: return SWL_24;
case 16: return SWL_16;
}
dev_err(dev, "unsupported slot width value: %d\n", width);
return 0;
}
unsigned int rsnd_ssi_clk_query(struct rsnd_dai *rdai,
int param1, int param2, int *idx) int param1, int param2, int *idx)
{ {
struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
int ssi_clk_mul_table[] = { int ssi_clk_mul_table[] = {
1, 2, 4, 8, 16, 6, 12, 1, 2, 4, 8, 16, 6, 12,
}; };
int j, ret; int j, ret;
unsigned int main_rate; unsigned int main_rate;
int width = rsnd_rdai_width_get(rdai);
for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) { for (j = 0; j < ARRAY_SIZE(ssi_clk_mul_table); j++) {
...@@ -240,12 +264,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv, ...@@ -240,12 +264,7 @@ unsigned int rsnd_ssi_clk_query(struct rsnd_priv *priv,
if (j == 0) if (j == 0)
continue; continue;
/* main_rate = width * param1 * param2 * ssi_clk_mul_table[j];
* this driver is assuming that
* system word is 32bit x chan
* see rsnd_ssi_init()
*/
main_rate = 32 * param1 * param2 * ssi_clk_mul_table[j];
ret = rsnd_adg_clk_query(priv, main_rate); ret = rsnd_adg_clk_query(priv, main_rate);
if (ret < 0) if (ret < 0)
...@@ -292,7 +311,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, ...@@ -292,7 +311,7 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
return 0; return 0;
} }
main_rate = rsnd_ssi_clk_query(priv, rate, chan, &idx); main_rate = rsnd_ssi_clk_query(rdai, rate, chan, &idx);
if (!main_rate) { if (!main_rate) {
dev_err(dev, "unsupported clock rate\n"); dev_err(dev, "unsupported clock rate\n");
return -EIO; return -EIO;
...@@ -312,7 +331,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod, ...@@ -312,7 +331,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_mod *mod,
* SSICR : FORCE, SCKD, SWSD * SSICR : FORCE, SCKD, SWSD
* SSIWSR : CONT * SSIWSR : CONT
*/ */
ssi->cr_clk = FORCE | SWL_32 | SCKD | SWSD | CKDV(idx); ssi->cr_clk = FORCE | rsnd_rdai_width_to_swl(rdai) |
SCKD | SWSD | CKDV(idx);
ssi->wsr = CONT; ssi->wsr = CONT;
ssi->rate = rate; ssi->rate = rate;
...@@ -357,11 +377,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod, ...@@ -357,11 +377,7 @@ static void rsnd_ssi_config_init(struct rsnd_mod *mod,
is_tdm = rsnd_runtime_is_ssi_tdm(io); is_tdm = rsnd_runtime_is_ssi_tdm(io);
/* cr_own |= FORCE | rsnd_rdai_width_to_swl(rdai);
* always use 32bit system word.
* see also rsnd_ssi_master_clk_enable()
*/
cr_own |= FORCE | SWL_32;
if (rdai->bit_clk_inv) if (rdai->bit_clk_inv)
cr_own |= SCKP; cr_own |= SCKP;
...@@ -494,7 +510,17 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod, ...@@ -494,7 +510,17 @@ static int rsnd_ssi_hw_params(struct rsnd_mod *mod,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod); struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
int chan = params_channels(params); int chan = params_channels(params);
unsigned int fmt_width = snd_pcm_format_width(params_format(params));
if (fmt_width > rdai->chan_width) {
struct rsnd_priv *priv = rsnd_io_to_priv(io);
struct device *dev = rsnd_priv_to_dev(priv);
dev_err(dev, "invalid combination of slot-width and format-data-width\n");
return -EINVAL;
}
/* /*
* snd_pcm_ops::hw_params will be called *before* * snd_pcm_ops::hw_params will be called *before*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment