summaryrefslogtreecommitdiff
path: root/sound/soc/sh/rcar/core.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-17 12:05:31 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-17 12:05:31 -0800
commita016af2e70bfca23f2f5de7d8708157b86ea374d (patch)
treebfe3c0c6ea9d52d4ec6ea021b0626a53c83e7d9f /sound/soc/sh/rcar/core.c
parente535d74bc50df2357d3253f8f3ca48c66d0d892a (diff)
parentc3b1681375dc6e71d89a3ae00cc3ce9e775a8917 (diff)
Merge tag 'sound-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "We've had quite busy weeks in this cycle. Looking at ALSA core, the significant changes are a few fixes wrt timer and sequencer ioctls that have been revealed by fuzzer recently. Other than that, ASoC core got a few updates about DAI link handling, but these are rather straightforward refactoring. In drivers scene, ASoC received quite lots of new drivers in addition to bunch of updates for still ongoing Intel Skylake support and topology API. HD-audio gained a new HDMI/DP hotplug notification via component. FireWire got a pile of code refactoring/updates with SCS.1x driver integration. More highlights are shown below. [ NOTE: this contains also many commits for DRM. This is due to the pull of drm stable branch into sound tree, as the base of i915 audio component work for HD-audio. The highlights below don't contain these DRM changes, as these are supposed to be pulled via drm tree in anyway sooner or later. ] Core: - Handful fixes to harden ALSA timer and sequencer ioctls against races reported by syzkaller fuzzer - Irq description string can be unique to each card; only for HD-audio for now ASoC: - Conversion of the array of DAI links to a list for supporting dynamically adding and removing DAI links - Topology API enhancements to make everything more component based and being able to specify PCM links via topology - Some more fixes for the topology code, though it is still not final and ready for enabling in production; we really need to get to the point where that can be done - A pile of changes for Intel SkyLake drivers which hopefully deliver some useful initial functionality for systems with this chipset, though there is more work still to come - Lots of new features and cleanups for the Renesas drivers - ANC support for WM5110 - New drivers: Imagination Technologies IPs, Atmel class D speaker, Cirrus CS47L24 and WM1831, Dialog DA7128, Realtek RT5659 and RT56156, Rockchip RK3036, TI PC3168A, and AMD ACP - Rename PCM1792a driver to be generic pcm179x HD-Audio: - Use audio component for i915 HDMI/DP hotplug handling - On-demand binding with i915 driver - bdl_pos_adj parameter adjustment for Baytrail controllers - Enable power_save_node for CX20722; this shouldn't lead to regression, hopefully - Kabylake HDMI/DP codec support - Quirks for Lenovo E50-80, Dell Latitude E-series, and other Dell machines - A few code refactoring FireWire: - Lots of code cleanup and refactoring - Integrate the support of SCS.1x devices into snd-oxfw driver; snd-scs1x driver is obsoleted USB-audio: - Fix possible NULL dereference at disconnection - A regression fix for Native Instruments devices Misc: - A few code cleanups of fm801 driver" * tag 'sound-4.5-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (722 commits) ALSA: timer: Code cleanup ALSA: timer: Harden slave timer list handling ALSA: hda - Add fixup for Dell Latitidue E6540 ALSA: timer: Fix race among timer ioctls ALSA: hda - add codec support for Kabylake display audio codec ALSA: timer: Fix double unlink of active_list ALSA: usb-audio: Fix mixer ctl regression of Native Instrument devices ALSA: hda - fix the headset mic detection problem for a Dell laptop ALSA: hda - Fix white noise on Dell Latitude E5550 ALSA: hda_intel: add card number to irq description ALSA: seq: Fix race at timer setup and close ALSA: seq: Fix missing NULL check at remove_events ioctl ALSA: usb-audio: Avoid calling usb_autopm_put_interface() at disconnect ASoC: hdac_hdmi: remove unused hdac_hdmi_query_pin_connlist ASoC: AMD: Add missing include file ALSA: hda - Fixup inverted internal mic for Lenovo E50-80 ALSA: usb: Add native DSD support for Oppo HA-1 ASoC: Make aux_dev more like a generic component ASoC: bcm2835: cleanup includes by ordering them alphabetically ASoC: AMD: Manage ACP 2.x SRAM banks power ...
Diffstat (limited to 'sound/soc/sh/rcar/core.c')
-rw-r--r--sound/soc/sh/rcar/core.c586
1 files changed, 216 insertions, 370 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index deed48ef28b8..02b4b085b8d7 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -99,34 +99,17 @@
#define RSND_RATES SNDRV_PCM_RATE_8000_96000
#define RSND_FMTS (SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE)
-static const struct rsnd_of_data rsnd_of_data_gen1 = {
- .flags = RSND_GEN1,
-};
-
-static const struct rsnd_of_data rsnd_of_data_gen2 = {
- .flags = RSND_GEN2,
-};
-
static const struct of_device_id rsnd_of_match[] = {
- { .compatible = "renesas,rcar_sound-gen1", .data = &rsnd_of_data_gen1 },
- { .compatible = "renesas,rcar_sound-gen2", .data = &rsnd_of_data_gen2 },
- { .compatible = "renesas,rcar_sound-gen3", .data = &rsnd_of_data_gen2 }, /* gen2 compatible */
+ { .compatible = "renesas,rcar_sound-gen1", .data = (void *)RSND_GEN1 },
+ { .compatible = "renesas,rcar_sound-gen2", .data = (void *)RSND_GEN2 },
+ { .compatible = "renesas,rcar_sound-gen3", .data = (void *)RSND_GEN2 }, /* gen2 compatible */
{},
};
MODULE_DEVICE_TABLE(of, rsnd_of_match);
/*
- * rsnd_platform functions
+ * rsnd_mod functions
*/
-#define rsnd_platform_call(priv, dai, func, param...) \
- (!(priv->info->func) ? 0 : \
- priv->info->func(param))
-
-#define rsnd_is_enable_path(io, name) \
- ((io)->info ? (io)->info->name : NULL)
-#define rsnd_info_id(priv, io, name) \
- ((io)->info->name - priv->info->name##_info)
-
void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
{
if (mod->type != type) {
@@ -138,9 +121,6 @@ void rsnd_mod_make_sure(struct rsnd_mod *mod, enum rsnd_mod_type type)
}
}
-/*
- * rsnd_mod functions
- */
char *rsnd_mod_name(struct rsnd_mod *mod)
{
if (!mod || !mod->ops)
@@ -192,19 +172,16 @@ void rsnd_mod_interrupt(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct rsnd_dai_stream *io;
struct rsnd_dai *rdai;
- int i, j;
-
- for_each_rsnd_dai(rdai, priv, j) {
+ int i;
- for (i = 0; i < RSND_MOD_MAX; i++) {
- io = &rdai->playback;
- if (mod == io->mod[i])
- callback(mod, io);
+ for_each_rsnd_dai(rdai, priv, i) {
+ io = &rdai->playback;
+ if (mod == io->mod[mod->type])
+ callback(mod, io);
- io = &rdai->capture;
- if (mod == io->mod[i])
- callback(mod, io);
- }
+ io = &rdai->capture;
+ if (mod == io->mod[mod->type])
+ callback(mod, io);
}
}
@@ -214,6 +191,43 @@ 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_get_slot_width(struct rsnd_dai_stream *io)
+{
+ struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
+ int chan = runtime->channels;
+
+ /* Multi channel Mode */
+ if (rsnd_ssi_multi_slaves(io))
+ chan /= rsnd_get_slot_num(io);
+
+ /* TDM Extend Mode needs 8ch */
+ if (chan == 6)
+ chan = 8;
+
+ return chan;
+}
+
/*
* ADINR function
*/
@@ -222,21 +236,17 @@ u32 rsnd_get_adinr_bit(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct device *dev = rsnd_priv_to_dev(priv);
- u32 adinr = runtime->channels;
switch (runtime->sample_bits) {
case 16:
- adinr |= (8 << 16);
- break;
+ return 8 << 16;
case 32:
- adinr |= (0 << 16);
- break;
- default:
- dev_warn(dev, "not supported sample bits\n");
- return 0;
+ return 0 << 16;
}
- return adinr;
+ dev_warn(dev, "not supported sample bits\n");
+
+ return 0;
}
u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
@@ -267,13 +277,22 @@ u32 rsnd_get_adinr_chan(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
*/
u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
{
- struct rsnd_mod *src = rsnd_io_to_mod_src(io);
struct rsnd_mod *ssi = rsnd_io_to_mod_ssi(io);
- struct rsnd_mod *target = src ? src : ssi;
+ struct rsnd_mod *target;
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 val = 0x76543210;
u32 mask = ~0;
+ if (rsnd_io_is_play(io)) {
+ struct rsnd_mod *src = rsnd_io_to_mod_src(io);
+
+ target = src ? src : ssi;
+ } else {
+ struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io);
+
+ target = cmd ? cmd : ssi;
+ }
+
mask <<= runtime->channels * 4;
val = val & mask;
@@ -300,20 +319,22 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
/*
* rsnd_dai functions
*/
-#define rsnd_mod_call(mod, io, func, param...) \
+#define rsnd_mod_call(idx, io, func, param...) \
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
+ struct rsnd_mod *mod = (io)->mod[idx]; \
struct device *dev = rsnd_priv_to_dev(priv); \
+ u32 *status = (io)->mod_status + idx; \
u32 mask = 0xF << __rsnd_mod_shift_##func; \
- u8 val = (mod->status >> __rsnd_mod_shift_##func) & 0xF; \
+ u8 val = (*status >> __rsnd_mod_shift_##func) & 0xF; \
u8 add = ((val + __rsnd_mod_add_##func) & 0xF); \
int ret = 0; \
int call = (val == __rsnd_mod_call_##func) && (mod)->ops->func; \
- mod->status = (mod->status & ~mask) + \
+ *status = (*status & ~mask) + \
(add << __rsnd_mod_shift_##func); \
dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \
rsnd_mod_name(mod), rsnd_mod_id(mod), \
- mod->status, call ? #func : ""); \
+ *status, call ? #func : ""); \
if (call) \
ret = (mod)->ops->func(mod, io, param); \
ret; \
@@ -327,13 +348,14 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io)
mod = (io)->mod[i]; \
if (!mod) \
continue; \
- ret |= rsnd_mod_call(mod, io, fn, param); \
+ ret |= rsnd_mod_call(i, io, fn, param); \
} \
ret; \
})
-static int rsnd_dai_connect(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+int rsnd_dai_connect(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
{
struct rsnd_priv *priv;
struct device *dev;
@@ -341,10 +363,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
if (!mod)
return -EIO;
+ if (io->mod[type])
+ return -EINVAL;
+
priv = rsnd_mod_to_priv(mod);
dev = rsnd_priv_to_dev(priv);
- io->mod[mod->type] = mod;
+ io->mod[type] = mod;
dev_dbg(dev, "%s[%d] is connected to io (%s)\n",
rsnd_mod_name(mod), rsnd_mod_id(mod),
@@ -354,9 +379,10 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
}
static void rsnd_dai_disconnect(struct rsnd_mod *mod,
- struct rsnd_dai_stream *io)
+ struct rsnd_dai_stream *io,
+ enum rsnd_mod_type type)
{
- io->mod[mod->type] = NULL;
+ io->mod[type] = NULL;
}
struct rsnd_dai *rsnd_rdai_get(struct rsnd_priv *priv, int id)
@@ -469,7 +495,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct rsnd_dai_stream *io = rsnd_rdai_to_io(rdai, substream);
- int ssi_id = rsnd_mod_id(rsnd_io_to_mod_ssi(io));
int ret;
unsigned long flags;
@@ -479,10 +504,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
case SNDRV_PCM_TRIGGER_START:
rsnd_dai_stream_init(io, substream);
- ret = rsnd_platform_call(priv, dai, start, ssi_id);
- if (ret < 0)
- goto dai_trigger_end;
-
ret = rsnd_dai_call(init, io, priv);
if (ret < 0)
goto dai_trigger_end;
@@ -496,8 +517,6 @@ static int rsnd_soc_dai_trigger(struct snd_pcm_substream *substream, int cmd,
ret |= rsnd_dai_call(quit, io, priv);
- ret |= rsnd_platform_call(priv, dai, stop, ssi_id);
-
rsnd_dai_stream_quit(io);
break;
default:
@@ -567,332 +586,157 @@ static int rsnd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return 0;
}
-static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
- .trigger = rsnd_soc_dai_trigger,
- .set_fmt = rsnd_soc_dai_set_fmt,
-};
-
-#define rsnd_path_add(priv, io, type) \
-({ \
- struct rsnd_mod *mod; \
- int ret = 0; \
- int id = -1; \
- \
- if (rsnd_is_enable_path(io, type)) { \
- id = rsnd_info_id(priv, io, type); \
- if (id >= 0) { \
- mod = rsnd_##type##_mod_get(priv, id); \
- ret = rsnd_dai_connect(mod, io); \
- } \
- } \
- ret; \
-})
-
-#define rsnd_path_remove(priv, io, type) \
-{ \
- struct rsnd_mod *mod; \
- int id = -1; \
- \
- if (rsnd_is_enable_path(io, type)) { \
- id = rsnd_info_id(priv, io, type); \
- if (id >= 0) { \
- mod = rsnd_##type##_mod_get(priv, id); \
- rsnd_dai_disconnect(mod, io); \
- } \
- } \
-}
-
-void rsnd_path_parse(struct rsnd_priv *priv,
- struct rsnd_dai_stream *io)
+static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai,
+ u32 tx_mask, u32 rx_mask,
+ int slots, int slot_width)
{
- struct rsnd_mod *dvc = rsnd_io_to_mod_dvc(io);
- struct rsnd_mod *mix = rsnd_io_to_mod_mix(io);
- struct rsnd_mod *src = rsnd_io_to_mod_src(io);
- struct rsnd_mod *cmd;
+ struct rsnd_priv *priv = rsnd_dai_to_priv(dai);
+ struct rsnd_dai *rdai = rsnd_dai_to_rdai(dai);
struct device *dev = rsnd_priv_to_dev(priv);
- u32 data;
- /* Gen1 is not supported */
- if (rsnd_is_gen1(priv))
- return;
-
- if (!mix && !dvc)
- return;
-
- if (mix) {
- struct rsnd_dai *rdai;
- int i;
- u32 path[] = {
- [0] = 0,
- [1] = 1 << 0,
- [2] = 0,
- [3] = 0,
- [4] = 0,
- [5] = 1 << 8
- };
-
- /*
- * it is assuming that integrater is well understanding about
- * data path. Here doesn't check impossible connection,
- * like src2 + src5
- */
- data = 0;
- for_each_rsnd_dai(rdai, priv, i) {
- io = &rdai->playback;
- if (mix == rsnd_io_to_mod_mix(io))
- data |= path[rsnd_mod_id(src)];
-
- io = &rdai->capture;
- if (mix == rsnd_io_to_mod_mix(io))
- data |= path[rsnd_mod_id(src)];
- }
-
- /*
- * We can't use ctu = rsnd_io_ctu() here.
- * Since, ID of dvc/mix are 0 or 1 (= same as CMD number)
- * but ctu IDs are 0 - 7 (= CTU00 - CTU13)
- */
- cmd = mix;
- } else {
- u32 path[] = {
- [0] = 0x30000,
- [1] = 0x30001,
- [2] = 0x40000,
- [3] = 0x10000,
- [4] = 0x20000,
- [5] = 0x40100
- };
-
- data = path[rsnd_mod_id(src)];
-
- cmd = dvc;
+ switch (slots) {
+ case 6:
+ /* TDM Extend Mode */
+ rsnd_set_slot(rdai, slots, 1);
+ break;
+ default:
+ dev_err(dev, "unsupported TDM slots (%d)\n", slots);
+ return -EINVAL;
}
- dev_dbg(dev, "ctu/mix path = 0x%08x", data);
-
- rsnd_mod_write(cmd, CMD_ROUTE_SLCT, data);
-
- rsnd_mod_write(cmd, CMD_CTRL, 0x10);
+ return 0;
}
-static int rsnd_path_init(struct rsnd_priv *priv,
- struct rsnd_dai *rdai,
- struct rsnd_dai_stream *io)
-{
- int ret;
-
- /*
- * Gen1 is created by SRU/SSI, and this SRU is base module of
- * Gen2's SCU/SSIU/SSI. (Gen2 SCU/SSIU came from SRU)
- *
- * Easy image is..
- * Gen1 SRU = Gen2 SCU + SSIU + etc
- *
- * Gen2 SCU path is very flexible, but, Gen1 SRU (SCU parts) is
- * using fixed path.
- */
-
- /* SSI */
- ret = rsnd_path_add(priv, io, ssi);
- if (ret < 0)
- return ret;
-
- /* SRC */
- ret = rsnd_path_add(priv, io, src);
- if (ret < 0)
- return ret;
+static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
+ .trigger = rsnd_soc_dai_trigger,
+ .set_fmt = rsnd_soc_dai_set_fmt,
+ .set_tdm_slot = rsnd_soc_set_dai_tdm_slot,
+};
- /* CTU */
- ret = rsnd_path_add(priv, io, ctu);
- if (ret < 0)
- return ret;
+void rsnd_parse_connect_common(struct rsnd_dai *rdai,
+ struct rsnd_mod* (*mod_get)(struct rsnd_priv *priv, int id),
+ struct device_node *node,
+ struct device_node *playback,
+ struct device_node *capture)
+{
+ struct rsnd_priv *priv = rsnd_rdai_to_priv(rdai);
+ struct device_node *np;
+ struct rsnd_mod *mod;
+ int i;
- /* MIX */
- ret = rsnd_path_add(priv, io, mix);
- if (ret < 0)
- return ret;
+ if (!node)
+ return;
- /* DVC */
- ret = rsnd_path_add(priv, io, dvc);
- if (ret < 0)
- return ret;
+ i = 0;
+ for_each_child_of_node(node, np) {
+ mod = mod_get(priv, i);
+ if (np == playback)
+ rsnd_dai_connect(mod, &rdai->playback, mod->type);
+ if (np == capture)
+ rsnd_dai_connect(mod, &rdai->capture, mod->type);
+ i++;
+ }
- return ret;
+ of_node_put(node);
}
-static void rsnd_of_parse_dai(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
+static int rsnd_dai_probe(struct rsnd_priv *priv)
{
- struct device_node *dai_node, *dai_np;
- struct device_node *ssi_node, *ssi_np;
- struct device_node *src_node, *src_np;
- struct device_node *ctu_node, *ctu_np;
- struct device_node *mix_node, *mix_np;
- struct device_node *dvc_node, *dvc_np;
+ struct device_node *dai_node;
+ struct device_node *dai_np;
struct device_node *playback, *capture;
- struct rsnd_dai_platform_info *dai_info;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct device *dev = &pdev->dev;
- int nr, i;
- int dai_i, ssi_i, src_i, ctu_i, mix_i, dvc_i;
-
- if (!of_data)
- return;
-
- dai_node = of_get_child_by_name(dev->of_node, "rcar_sound,dai");
- if (!dai_node)
- return;
+ struct rsnd_dai_stream *io_playback;
+ struct rsnd_dai_stream *io_capture;
+ struct snd_soc_dai_driver *rdrv, *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)
- return;
+ if (!nr) {
+ ret = -EINVAL;
+ goto rsnd_dai_probe_done;
+ }
- dai_info = devm_kzalloc(dev,
- sizeof(struct rsnd_dai_platform_info) * nr,
- GFP_KERNEL);
- if (!dai_info) {
- dev_err(dev, "dai info allocation error\n");
- return;
+ 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;
}
- info->dai_info_nr = nr;
- info->dai_info = dai_info;
-
- ssi_node = of_get_child_by_name(dev->of_node, "rcar_sound,ssi");
- src_node = of_get_child_by_name(dev->of_node, "rcar_sound,src");
- ctu_node = of_get_child_by_name(dev->of_node, "rcar_sound,ctu");
- mix_node = of_get_child_by_name(dev->of_node, "rcar_sound,mix");
- dvc_node = of_get_child_by_name(dev->of_node, "rcar_sound,dvc");
-
-#define mod_parse(name) \
-if (name##_node) { \
- struct rsnd_##name##_platform_info *name##_info; \
- \
- name##_i = 0; \
- for_each_child_of_node(name##_node, name##_np) { \
- name##_info = info->name##_info + name##_i; \
- \
- if (name##_np == playback) \
- dai_info->playback.name = name##_info; \
- if (name##_np == capture) \
- dai_info->capture.name = name##_info; \
- \
- name##_i++; \
- } \
-}
+ priv->rdai_nr = nr;
+ priv->daidrv = rdrv;
+ priv->rdai = rdai;
/*
* parse all dai
*/
dai_i = 0;
for_each_child_of_node(dai_node, dai_np) {
- dai_info = info->dai_info + dai_i;
-
- for (i = 0;; i++) {
-
- playback = of_parse_phandle(dai_np, "playback", i);
- capture = of_parse_phandle(dai_np, "capture", i);
+ 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;
- mod_parse(ssi);
- mod_parse(src);
- mod_parse(ctu);
- mod_parse(mix);
- mod_parse(dvc);
+ 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);
}
dai_i++;
- }
-}
-
-static int rsnd_dai_probe(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv)
-{
- struct snd_soc_dai_driver *drv;
- struct rcar_snd_info *info = rsnd_priv_to_info(priv);
- struct rsnd_dai *rdai;
- struct rsnd_ssi_platform_info *pmod, *cmod;
- struct device *dev = rsnd_priv_to_dev(priv);
- int dai_nr;
- int i;
-
- rsnd_of_parse_dai(pdev, of_data, priv);
- dai_nr = info->dai_info_nr;
- if (!dai_nr) {
- dev_err(dev, "no dai\n");
- return -EIO;
+ 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" : " -- ");
}
- drv = devm_kzalloc(dev, sizeof(*drv) * dai_nr, GFP_KERNEL);
- rdai = devm_kzalloc(dev, sizeof(*rdai) * dai_nr, GFP_KERNEL);
- if (!drv || !rdai) {
- dev_err(dev, "dai allocate failed\n");
- return -ENOMEM;
- }
-
- priv->rdai_nr = dai_nr;
- priv->daidrv = drv;
- priv->rdai = rdai;
+ ret = 0;
- for (i = 0; i < dai_nr; i++) {
+rsnd_dai_probe_done:
+ of_node_put(dai_node);
- pmod = info->dai_info[i].playback.ssi;
- cmod = info->dai_info[i].capture.ssi;
-
- /*
- * init rsnd_dai
- */
- snprintf(rdai[i].name, RSND_DAI_NAME_SIZE, "rsnd-dai.%d", i);
- rdai[i].priv = priv;
-
- /*
- * init snd_soc_dai_driver
- */
- drv[i].name = rdai[i].name;
- drv[i].ops = &rsnd_soc_dai_ops;
- if (pmod) {
- snprintf(rdai[i].playback.name, RSND_DAI_NAME_SIZE,
- "DAI%d Playback", i);
-
- drv[i].playback.rates = RSND_RATES;
- drv[i].playback.formats = RSND_FMTS;
- drv[i].playback.channels_min = 2;
- drv[i].playback.channels_max = 2;
- drv[i].playback.stream_name = rdai[i].playback.name;
-
- rdai[i].playback.info = &info->dai_info[i].playback;
- rdai[i].playback.rdai = rdai + i;
- rsnd_path_init(priv, &rdai[i], &rdai[i].playback);
- }
- if (cmod) {
- snprintf(rdai[i].capture.name, RSND_DAI_NAME_SIZE,
- "DAI%d Capture", i);
-
- drv[i].capture.rates = RSND_RATES;
- drv[i].capture.formats = RSND_FMTS;
- drv[i].capture.channels_min = 2;
- drv[i].capture.channels_max = 2;
- drv[i].capture.stream_name = rdai[i].capture.name;
-
- rdai[i].capture.info = &info->dai_info[i].capture;
- rdai[i].capture.rdai = rdai + i;
- rsnd_path_init(priv, &rdai[i], &rdai[i].capture);
- }
-
- dev_dbg(dev, "%s (%s/%s)\n", rdai[i].name,
- pmod ? "play" : " -- ",
- cmod ? "capture" : " -- ");
- }
-
- return 0;
+ return ret;
}
/*
@@ -1033,14 +877,13 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod,
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod))
{
- struct snd_soc_card *soc_card = rtd->card;
struct snd_card *card = rtd->card->snd_card;
struct snd_kcontrol *kctrl;
struct snd_kcontrol_new knew = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = name,
.info = rsnd_kctrl_info,
- .index = rtd - soc_card->rtd,
+ .index = rtd->num,
.get = rsnd_kctrl_get,
.put = rsnd_kctrl_put,
.private_value = (unsigned long)cfg,
@@ -1077,10 +920,14 @@ int rsnd_kctrl_new_m(struct rsnd_mod *mod,
void (*update)(struct rsnd_dai_stream *io,
struct rsnd_mod *mod),
struct rsnd_kctrl_cfg_m *_cfg,
+ int ch_size,
u32 max)
{
+ if (ch_size > RSND_DVC_CHANNELS)
+ return -EINVAL;
+
_cfg->cfg.max = max;
- _cfg->cfg.size = RSND_DVC_CHANNELS;
+ _cfg->cfg.size = ch_size;
_cfg->cfg.val = _cfg->val;
return __rsnd_kctrl_new(mod, io, rtd, name, &_cfg->cfg, update);
}
@@ -1161,6 +1008,9 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
ret = rsnd_dai_call(probe, io, priv);
if (ret == -EAGAIN) {
+ struct rsnd_mod *ssi_mod = rsnd_io_to_mod_ssi(io);
+ int i;
+
/*
* Fallback to PIO mode
*/
@@ -1175,10 +1025,12 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
rsnd_dai_call(remove, io, priv);
/*
- * remove SRC/DVC from DAI,
+ * remove all mod from io
+ * and, re connect ssi
*/
- rsnd_path_remove(priv, io, src);
- rsnd_path_remove(priv, io, dvc);
+ for (i = 0; i < RSND_MOD_MAX; i++)
+ rsnd_dai_disconnect((io)->mod[i], io, i);
+ rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI);
/*
* fallback
@@ -1200,33 +1052,25 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
*/
static int rsnd_probe(struct platform_device *pdev)
{
- struct rcar_snd_info *info;
struct rsnd_priv *priv;
struct device *dev = &pdev->dev;
struct rsnd_dai *rdai;
const struct of_device_id *of_id = of_match_device(rsnd_of_match, dev);
- const struct rsnd_of_data *of_data;
- int (*probe_func[])(struct platform_device *pdev,
- const struct rsnd_of_data *of_data,
- struct rsnd_priv *priv) = {
+ int (*probe_func[])(struct rsnd_priv *priv) = {
rsnd_gen_probe,
rsnd_dma_probe,
rsnd_ssi_probe,
+ rsnd_ssiu_probe,
rsnd_src_probe,
rsnd_ctu_probe,
rsnd_mix_probe,
rsnd_dvc_probe,
+ rsnd_cmd_probe,
rsnd_adg_probe,
rsnd_dai_probe,
};
int ret, i;
- info = devm_kzalloc(&pdev->dev, sizeof(struct rcar_snd_info),
- GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- of_data = of_id->data;
-
/*
* init priv data
*/
@@ -1237,14 +1081,14 @@ static int rsnd_probe(struct platform_device *pdev)
}
priv->pdev = pdev;
- priv->info = info;
+ priv->flags = (unsigned long)of_id->data;
spin_lock_init(&priv->lock);
/*
* init each module
*/
for (i = 0; i < ARRAY_SIZE(probe_func); i++) {
- ret = probe_func[i](pdev, of_data, priv);
+ ret = probe_func[i](priv);
if (ret)
return ret;
}
@@ -1297,13 +1141,15 @@ static int rsnd_remove(struct platform_device *pdev)
{
struct rsnd_priv *priv = dev_get_drvdata(&pdev->dev);
struct rsnd_dai *rdai;
- void (*remove_func[])(struct platform_device *pdev,
- struct rsnd_priv *priv) = {
+ void (*remove_func[])(struct rsnd_priv *priv) = {
rsnd_ssi_remove,
+ rsnd_ssiu_remove,
rsnd_src_remove,
rsnd_ctu_remove,
rsnd_mix_remove,
rsnd_dvc_remove,
+ rsnd_cmd_remove,
+ rsnd_adg_remove,
};
int ret = 0, i;
@@ -1315,7 +1161,7 @@ static int rsnd_remove(struct platform_device *pdev)
}
for (i = 0; i < ARRAY_SIZE(remove_func); i++)
- remove_func[i](pdev, priv);
+ remove_func[i](priv);
snd_soc_unregister_component(&pdev->dev);
snd_soc_unregister_platform(&pdev->dev);