aboutsummaryrefslogtreecommitdiffstats
path: root/sound/soc/sh/rcar/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/sh/rcar/core.c')
-rw-r--r--sound/soc/sh/rcar/core.c547
1 files changed, 400 insertions, 147 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 1744015408c3..3f2ced26ed37 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -203,27 +203,6 @@ int rsnd_io_is_working(struct rsnd_dai_stream *io)
return !!io->substream;
}
-void rsnd_set_slot(struct rsnd_dai *rdai,
- int slots, int num)
-{
- rdai->slots = slots;
- rdai->slots_num = num;
-}
-
-int rsnd_get_slot(struct rsnd_dai_stream *io)
-{
- struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-
- return rdai->slots;
-}
-
-int rsnd_get_slot_num(struct rsnd_dai_stream *io)
-{
- struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
-
- return rdai->slots_num;
-}
-
int rsnd_runtime_channel_original(struct rsnd_dai_stream *io)
{
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
@@ -248,13 +227,14 @@ int rsnd_runtime_channel_after_ctu(struct rsnd_dai_stream *io)
int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
{
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
int chan = rsnd_io_is_play(io) ?
rsnd_runtime_channel_after_ctu(io) :
rsnd_runtime_channel_original(io);
/* Use Multi SSI */
if (rsnd_runtime_is_ssi_multi(io))
- chan /= rsnd_get_slot_num(io);
+ chan /= rsnd_rdai_ssi_lane_get(rdai);
/* TDM Extend Mode needs 8ch */
if (chan == 6)
@@ -265,12 +245,13 @@ int rsnd_runtime_channel_for_ssi(struct rsnd_dai_stream *io)
int rsnd_runtime_is_ssi_multi(struct rsnd_dai_stream *io)
{
- int slots = rsnd_get_slot_num(io);
+ struct rsnd_dai *rdai = rsnd_io_to_rdai(io);
+ int lane = rsnd_rdai_ssi_lane_get(rdai);
int chan = rsnd_io_is_play(io) ?
rsnd_runtime_channel_after_ctu(io) :
rsnd_runtime_channel_original(io);
- return (chan >= 6) && (slots > 1);
+ return (chan > 2) && (lane > 1);
}
int rsnd_runtime_is_ssi_tdm(struct rsnd_dai_stream *io)
@@ -310,6 +291,24 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
u32 val = 0x76543210;
u32 mask = ~0;
+ /*
+ * *Hardware* L/R and *Software* L/R are inverted.
+ * We need to care about inversion timing to control
+ * Playback/Capture correctly.
+ * The point is [DVC] needs *Hardware* L/R, [MEM] needs *Software* L/R
+ *
+ * sL/R : software L/R
+ * hL/R : hardware L/R
+ * (*) : conversion timing
+ *
+ * Playback
+ * sL/R (*) hL/R hL/R hL/R hL/R hL/R
+ * [MEM] -> [SRC] -> [DVC] -> [CMD] -> [SSIU] -> [SSI] -> codec
+ *
+ * Capture
+ * hL/R hL/R hL/R hL/R hL/R (*) sL/R
+ * codec -> [SSI] -> [SSIU] -> [SRC] -> [DVC] -> [CMD] -> [MEM]
+ */
if (rsnd_io_is_play(io)) {
struct rsnd_mod *src = rsnd_io_to_mod_src(io);
@@ -343,6 +342,57 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
return 0x76543210;
}
+u32 rsnd_get_busif_shift(struct rsnd_dai_stream *io, struct rsnd_mod *mod)
+{
+ enum rsnd_mod_type playback_mods[] = {
+ RSND_MOD_SRC,
+ RSND_MOD_CMD,
+ RSND_MOD_SSIU,
+ };
+ enum rsnd_mod_type capture_mods[] = {
+ RSND_MOD_CMD,
+ RSND_MOD_SRC,
+ RSND_MOD_SSIU,
+ };
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ struct rsnd_mod *tmod = NULL;
+ enum rsnd_mod_type *mods =
+ rsnd_io_is_play(io) ?
+ playback_mods : capture_mods;
+ int i;
+
+ /*
+ * This is needed for 24bit data
+ * We need to shift 8bit
+ *
+ * Linux 24bit data is located as 0x00******
+ * HW 24bit data is located as 0x******00
+ *
+ */
+ switch (runtime->sample_bits) {
+ case 16:
+ return 0;
+ case 32:
+ break;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(playback_mods); i++) {
+ tmod = rsnd_io_to_mod(io, mods[i]);
+ if (tmod)
+ break;
+ }
+
+ if (tmod != mod)
+ return 0;
+
+ if (rsnd_io_is_play(io))
+ return (0 << 20) | /* shift to Left */
+ (8 << 16); /* 8bit */
+ else
+ return (1 << 20) | /* shift to Right */
+ (8 << 16); /* 8bit */
+}
+
/*
* rsnd_dai functions
*/
@@ -419,8 +469,7 @@ static int rsnd_status_update(u32 *status,
#define rsnd_dai_call(fn, io, param...) \
({ \
- struct rsnd_priv *priv = rsnd_io_to_priv(io); \
- struct device *dev = rsnd_priv_to_dev(priv); \
+ struct device *dev = rsnd_priv_to_dev(rsnd_io_to_priv(io)); \
struct rsnd_mod *mod; \
int is_play = rsnd_io_is_play(io); \
int ret = 0, i; \
@@ -481,6 +530,24 @@ static void rsnd_dai_disconnect(struct rsnd_mod *mod,
io->mod[type] = NULL;
}
+int rsnd_rdai_channels_ctrl(struct rsnd_dai *rdai,
+ int max_channels)
+{
+ if (max_channels > 0)
+ rdai->max_channels = max_channels;
+
+ return rdai->max_channels;
+}
+
+int rsnd_rdai_ssi_lane_ctrl(struct rsnd_dai *rdai,
+ int ssi_lane)
+{
+ if (ssi_lane > 0)
+ rdai->ssi_lane = ssi_lane;
+
+ return rdai->ssi_lane;
+}
+
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
{
if ((id < 0) || (id >= rsnd_rdai_nr(priv)))
@@ -500,40 +567,6 @@ static struct rsnd_dai *rsnd_dai_to_rdai(struct snd_soc_dai *dai)
/*
* rsnd_soc_dai functions
*/
-int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional)
-{
- struct snd_pcm_substream *substream = io->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int pos = io->byte_pos + additional;
-
- pos %= (runtime->periods * io->byte_per_period);
-
- return pos;
-}
-
-bool rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int byte)
-{
- io->byte_pos += byte;
-
- if (io->byte_pos >= io->next_period_byte) {
- struct snd_pcm_substream *substream = io->substream;
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- io->period_pos++;
- io->next_period_byte += io->byte_per_period;
-
- if (io->period_pos >= runtime->periods) {
- io->byte_pos = 0;
- io->period_pos = 0;
- io->next_period_byte = io->byte_per_period;
- }
-
- return true;
- }
-
- return false;
-}
-
void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
{
struct snd_pcm_substream *substream = io->substream;
@@ -551,15 +584,7 @@ void rsnd_dai_period_elapsed(struct rsnd_dai_stream *io)
static void rsnd_dai_stream_init(struct rsnd_dai_stream *io,
struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
-
io->substream = substream;
- io->byte_pos = 0;
- io->period_pos = 0;
- io->byte_per_period = runtime->period_size *
- runtime->channels *
- samples_to_bytes(runtime, 1);
- io->next_period_byte = io->byte_per_period;
}
static void rsnd_dai_stream_quit(struct rsnd_dai_stream *io)
@@ -698,9 +723,13 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
struct device *dev = rsnd_priv_to_dev(priv);
switch (slots) {
+ case 2:
case 6:
+ case 8:
+ case 16:
/* TDM Extend Mode */
- rsnd_set_slot(rdai, slots, 1);
+ rsnd_rdai_channels_set(rdai, slots);
+ rsnd_rdai_ssi_lane_set(rdai, 1);
break;
default:
dev_err(dev, "unsupported TDM slots (%d)\n", slots);
@@ -710,22 +739,177 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
+static unsigned int rsnd_soc_hw_channels_list[] = {
+ 2, 6, 8, 16,
+};
+
+static unsigned int rsnd_soc_hw_rate_list[] = {
+ 8000,
+ 11025,
+ 16000,
+ 22050,
+ 32000,
+ 44100,
+ 48000,
+ 64000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+};
+
+static int rsnd_soc_hw_rule(struct rsnd_priv *priv,
+ unsigned int *list, int list_num,
+ struct snd_interval *baseline, struct snd_interval *iv)
+{
+ struct snd_interval p;
+ unsigned int rate;
+ int i;
+
+ snd_interval_any(&p);
+ p.min = UINT_MAX;
+ p.max = 0;
+
+ for (i = 0; i < list_num; i++) {
+
+ if (!snd_interval_test(iv, list[i]))
+ continue;
+
+ rate = rsnd_ssi_clk_query(priv,
+ baseline->min, list[i], NULL);
+ if (rate > 0) {
+ p.min = min(p.min, list[i]);
+ p.max = max(p.max, list[i]);
+ }
+
+ rate = rsnd_ssi_clk_query(priv,
+ baseline->max, list[i], NULL);
+ if (rate > 0) {
+ p.min = min(p.min, list[i]);
+ p.max = max(p.max, list[i]);
+ }
+ }
+
+ return snd_interval_refine(iv, &p);
+}
+
+static int rsnd_soc_hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ 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 ic;
+ struct snd_soc_dai *dai = rule->private;
+ struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+
+ /*
+ * possible sampling rate limitation is same as
+ * 2ch if it supports multi ssi
+ */
+ ic = *ic_;
+ if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
+ ic.min = 2;
+ ic.max = 2;
+ }
+
+ return rsnd_soc_hw_rule(priv, rsnd_soc_hw_rate_list,
+ ARRAY_SIZE(rsnd_soc_hw_rate_list),
+ &ic, ir);
+}
+
+
+static int rsnd_soc_hw_rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ 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 ic;
+ struct snd_soc_dai *dai = rule->private;
+ struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+
+ /*
+ * possible sampling rate limitation is same as
+ * 2ch if it supports multi ssi
+ */
+ ic = *ic_;
+ if (1 < rsnd_rdai_ssi_lane_get(rdai)) {
+ ic.min = 2;
+ ic.max = 2;
+ }
+
+ return rsnd_soc_hw_rule(priv, rsnd_soc_hw_channels_list,
+ ARRAY_SIZE(rsnd_soc_hw_channels_list),
+ ir, &ic);
+}
+
+static void rsnd_soc_hw_constraint(struct snd_pcm_runtime *runtime,
+ struct snd_soc_dai *dai)
+{
+ struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct snd_pcm_hw_constraint_list *constraint = &rdai->constraint;
+ unsigned int max_channels = rsnd_rdai_channels_get(rdai);
+ int i;
+
+ /*
+ * Channel Limitation
+ * It depends on Platform design
+ */
+ constraint->list = rsnd_soc_hw_channels_list;
+ constraint->count = 0;
+ constraint->mask = 0;
+
+ for (i = 0; i < ARRAY_SIZE(rsnd_soc_hw_channels_list); i++) {
+ if (rsnd_soc_hw_channels_list[i] > max_channels)
+ break;
+ constraint->count = i + 1;
+ }
+
+ snd_pcm_hw_constraint_list(runtime, 0,
+ SNDRV_PCM_HW_PARAM_CHANNELS, constraint);
+
+ /*
+ * Sampling Rate / Channel Limitation
+ * It depends on Clock Master Mode
+ */
+ if (!rsnd_rdai_is_clk_master(rdai))
+ return;
+
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ rsnd_soc_hw_rule_rate, dai,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ rsnd_soc_hw_rule_channels, dai,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+}
+
static int rsnd_soc_dai_startup(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+ int ret;
+
+ /* rsnd_io_to_runtime() is not yet enabled here */
+ rsnd_soc_hw_constraint(substream->runtime, dai);
/*
* call rsnd_dai_call without spinlock
*/
- return rsnd_dai_call(nolock_start, io, priv);
+ ret = rsnd_dai_call(nolock_start, io, priv);
+ if (ret < 0)
+ rsnd_dai_call(nolock_stop, io, priv);
+
+ return ret;
}
static void rsnd_soc_dai_shutdown(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
/*
@@ -769,32 +953,132 @@ void rsnd_parse_connect_common(struct rsnd_dai *rdai,
of_node_put(node);
}
-static int rsnd_dai_probe(struct rsnd_priv *priv)
+static struct device_node *rsnd_dai_of_node(struct rsnd_priv *priv,
+ int *is_graph)
{
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct device_node *np = dev->of_node;
struct device_node *dai_node;
- struct device_node *dai_np;
+ struct device_node *ret;
+
+ *is_graph = 0;
+
+ /*
+ * parse both previous dai (= rcar_sound,dai), and
+ * graph dai (= ports/port)
+ */
+ dai_node = of_get_child_by_name(np, RSND_NODE_DAI);
+ if (dai_node) {
+ ret = dai_node;
+ goto of_node_compatible;
+ }
+
+ ret = np;
+
+ dai_node = of_graph_get_next_endpoint(np, NULL);
+ if (dai_node)
+ goto of_node_graph;
+
+ return NULL;
+
+of_node_graph:
+ *is_graph = 1;
+of_node_compatible:
+ of_node_put(dai_node);
+
+ return ret;
+}
+
+static void __rsnd_dai_probe(struct rsnd_priv *priv,
+ struct device_node *dai_np,
+ int dai_i, int is_graph)
+{
struct device_node *playback, *capture;
struct rsnd_dai_stream *io_playback;
struct rsnd_dai_stream *io_capture;
- struct snd_soc_dai_driver *rdrv, *drv;
+ struct snd_soc_dai_driver *drv;
struct rsnd_dai *rdai;
struct device *dev = rsnd_priv_to_dev(priv);
- int nr, dai_i, io_i;
- int ret;
-
- dai_node = rsnd_dai_of_node(priv);
- nr = of_get_child_count(dai_node);
- if (!nr) {
- ret = -EINVAL;
- goto rsnd_dai_probe_done;
+ int io_i;
+
+ rdai = rsnd_rdai_get(priv, dai_i);
+ drv = priv->daidrv + dai_i;
+ io_playback = &rdai->playback;
+ io_capture = &rdai->capture;
+
+ snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
+
+ rdai->priv = priv;
+ drv->name = rdai->name;
+ drv->ops = &rsnd_soc_dai_ops;
+
+ snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
+ "DAI%d Playback", dai_i);
+ drv->playback.rates = RSND_RATES;
+ drv->playback.formats = RSND_FMTS;
+ drv->playback.channels_min = 2;
+ drv->playback.channels_max = 16;
+ drv->playback.stream_name = rdai->playback.name;
+
+ snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
+ "DAI%d Capture", dai_i);
+ drv->capture.rates = RSND_RATES;
+ drv->capture.formats = RSND_FMTS;
+ drv->capture.channels_min = 2;
+ drv->capture.channels_max = 16;
+ drv->capture.stream_name = rdai->capture.name;
+
+ rdai->playback.rdai = rdai;
+ rdai->capture.rdai = rdai;
+ rsnd_rdai_channels_set(rdai, 2); /* default 2ch */
+ rsnd_rdai_ssi_lane_set(rdai, 1); /* default 1lane */
+
+ for (io_i = 0;; io_i++) {
+ playback = of_parse_phandle(dai_np, "playback", io_i);
+ capture = of_parse_phandle(dai_np, "capture", io_i);
+
+ if (!playback && !capture)
+ break;
+
+ rsnd_parse_connect_ssi(rdai, playback, capture);
+ rsnd_parse_connect_src(rdai, playback, capture);
+ rsnd_parse_connect_ctu(rdai, playback, capture);
+ rsnd_parse_connect_mix(rdai, playback, capture);
+ rsnd_parse_connect_dvc(rdai, playback, capture);
+
+ of_node_put(playback);
+ of_node_put(capture);
}
+ dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
+ rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
+ rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
+}
+
+static int rsnd_dai_probe(struct rsnd_priv *priv)
+{
+ struct device_node *dai_node;
+ struct device_node *dai_np;
+ struct snd_soc_dai_driver *rdrv;
+ struct device *dev = rsnd_priv_to_dev(priv);
+ struct rsnd_dai *rdai;
+ int nr;
+ int is_graph;
+ int dai_i;
+
+ dai_node = rsnd_dai_of_node(priv, &is_graph);
+ if (is_graph)
+ nr = of_graph_get_endpoint_count(dai_node);
+ else
+ nr = of_get_child_count(dai_node);
+
+ if (!nr)
+ return -EINVAL;
+
rdrv = devm_kzalloc(dev, sizeof(*rdrv) * nr, GFP_KERNEL);
rdai = devm_kzalloc(dev, sizeof(*rdai) * nr, GFP_KERNEL);
- if (!rdrv || !rdai) {
- ret = -ENOMEM;
- goto rsnd_dai_probe_done;
- }
+ if (!rdrv || !rdai)
+ return -ENOMEM;
priv->rdai_nr = nr;
priv->daidrv = rdrv;
@@ -804,68 +1088,18 @@ static int rsnd_dai_probe(struct rsnd_priv *priv)
* parse all dai
*/
dai_i = 0;
- for_each_child_of_node(dai_node, dai_np) {
- rdai = rsnd_rdai_get(priv, dai_i);
- drv = rdrv + dai_i;
- io_playback = &rdai->playback;
- io_capture = &rdai->capture;
-
- snprintf(rdai->name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", dai_i);
-
- rdai->priv = priv;
- drv->name = rdai->name;
- drv->ops = &rsnd_soc_dai_ops;
-
- snprintf(rdai->playback.name, RSND_DAI_NAME_SIZE,
- "DAI%d Playback", dai_i);
- drv->playback.rates = RSND_RATES;
- drv->playback.formats = RSND_FMTS;
- drv->playback.channels_min = 2;
- drv->playback.channels_max = 6;
- drv->playback.stream_name = rdai->playback.name;
-
- snprintf(rdai->capture.name, RSND_DAI_NAME_SIZE,
- "DAI%d Capture", dai_i);
- drv->capture.rates = RSND_RATES;
- drv->capture.formats = RSND_FMTS;
- drv->capture.channels_min = 2;
- drv->capture.channels_max = 6;
- drv->capture.stream_name = rdai->capture.name;
-
- rdai->playback.rdai = rdai;
- rdai->capture.rdai = rdai;
- rsnd_set_slot(rdai, 2, 1); /* default */
-
- for (io_i = 0;; io_i++) {
- playback = of_parse_phandle(dai_np, "playback", io_i);
- capture = of_parse_phandle(dai_np, "capture", io_i);
-
- if (!playback && !capture)
- break;
-
- rsnd_parse_connect_ssi(rdai, playback, capture);
- rsnd_parse_connect_src(rdai, playback, capture);
- rsnd_parse_connect_ctu(rdai, playback, capture);
- rsnd_parse_connect_mix(rdai, playback, capture);
- rsnd_parse_connect_dvc(rdai, playback, capture);
-
- of_node_put(playback);
- of_node_put(capture);
+ if (is_graph) {
+ for_each_endpoint_of_node(dai_node, dai_np) {
+ __rsnd_dai_probe(priv, dai_np, dai_i, is_graph);
+ rsnd_ssi_parse_hdmi_connection(priv, dai_np, dai_i);
+ dai_i++;
}
-
- dai_i++;
-
- dev_dbg(dev, "%s (%s/%s)\n", rdai->name,
- rsnd_io_to_mod_ssi(io_playback) ? "play" : " -- ",
- rsnd_io_to_mod_ssi(io_capture) ? "capture" : " -- ");
+ } else {
+ for_each_child_of_node(dai_node, dai_np)
+ __rsnd_dai_probe(priv, dai_np, dai_i++, is_graph);
}
- ret = 0;
-
-rsnd_dai_probe_done:
- of_node_put(dai_node);
-
- return ret;
+ return 0;
}
/*
@@ -914,12 +1148,14 @@ static int rsnd_hw_params(struct snd_pcm_substream *substream,
static snd_pcm_uframes_t rsnd_pointer(struct snd_pcm_substream *substream)
{
- struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_soc_dai *dai = rsnd_substream_to_dai(substream);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
+ snd_pcm_uframes_t pointer = 0;
+
+ rsnd_dai_call(pointer, io, &pointer);
- return bytes_to_frames(runtime, io->byte_pos);
+ return pointer;
}
static struct snd_pcm_ops rsnd_pcm_ops = {
@@ -982,6 +1218,9 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
int i, change = 0;
+ if (!cfg->accept(cfg->io))
+ return 0;
+
for (i = 0; i < cfg->size; i++) {
if (cfg->texts) {
change |= (uc->value.enumerated.item[i] != cfg->val[i]);
@@ -998,6 +1237,18 @@ static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
return change;
}
+int rsnd_kctrl_accept_anytime(struct rsnd_dai_stream *io)
+{
+ return 1;
+}
+
+int rsnd_kctrl_accept_runtime(struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+
+ return !!runtime;
+}
+
struct rsnd_kctrl_cfg *rsnd_kctrl_init_m(struct rsnd_kctrl_cfg_m *cfg)
{
cfg->cfg.val = cfg->val;
@@ -1016,6 +1267,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
struct rsnd_dai_stream *io,
struct snd_soc_pcm_runtime *rtd,
const unsigned char *name,
+ int (*accept)(struct rsnd_dai_stream *io),
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod),
struct rsnd_kctrl_cfg *cfg,
@@ -1050,6 +1302,7 @@ int rsnd_kctrl_new(struct rsnd_mod *mod,
cfg->texts = texts;
cfg->max = max;
cfg->size = size;
+ cfg->accept = accept;
cfg->update = update;
cfg->card = card;
cfg->kctrl = kctrl;
@@ -1281,7 +1534,7 @@ static int rsnd_resume(struct device *dev)
return 0;
}
-static struct dev_pm_ops rsnd_pm_ops = {
+static const struct dev_pm_ops rsnd_pm_ops = {
.suspend = rsnd_suspend,
.resume = rsnd_resume,
};