diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 11:14:28 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-12-14 11:14:28 -0800 |
commit | ce38207f161513ee3d2bd3860489f07ebe65bc78 (patch) | |
tree | b3ad9e8a5e087b91d9f30a314c55df5fa70c142e /sound/soc/sh/rcar/core.c | |
parent | Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial (diff) | |
parent | ALSA: hiface: Fix M2Tech hiFace driver sampling rate change (diff) | |
download | linux-dev-ce38207f161513ee3d2bd3860489f07ebe65bc78.tar.xz linux-dev-ce38207f161513ee3d2bd3860489f07ebe65bc78.zip |
Merge tag 'sound-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"No dramatic changes are found in this development cycle, but as usual,
many commits are applied in a wide range of drivers.
Most of big changes are in ASoC, where a few bits of framework work
and quite a lot of cleanups and improvements to existing code have
been done. The rest are usual stuff, a few HD-audio and USB-audio
quirks and fixes, as well as the drop of kthread usages in the whole
subsystem.
Below are some highlights:
ASoC:
- support for stereo DAPM controls
- some initial work on the of-graph sound card
- regmap conversions of the remaining AC'97 drivers
- a new version of the topology ABI; this should be backward
compatible
- updates / cleanups of rsnd, sunxi, sti, nau8825, samsung, arizona,
Intel skylake, atom-sst
- new drivers for Cirrus Logic CS42L42, Qualcomm MSM8916-WCD, and
Realtek RT5665
USB-audio:
- yet another race fix at disconnection
- tolerated packet size calculation for some Android devices
- quirks for Axe-Fx II, QuickCam, TEAC 501/503
HD-audio:
- improvement of Dell pin fixup mapping
- quirks for HP Z1 Gen3, Alienware 15 R2 2016 and ALC622 headset mic
Misc:
- replace all kthread usages with simple works"
* tag 'sound-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (296 commits)
ALSA: hiface: Fix M2Tech hiFace driver sampling rate change
ALSA: usb-audio: Eliminate noise at the start of DSD playback.
ALSA: usb-audio: Add native DSD support for TEAC 501/503 DAC
ASoC: wm_adsp: wm_adsp_buf_alloc should use kfree in error path
ASoC: topology: avoid uninitialized kcontrol_type
ALSA: usb-audio: Add QuickCam Communicate Deluxe/S7500 to volume_control_quirks
ALSA: usb-audio: add implicit fb quirk for Axe-Fx II
ASoC: zte: spdif: correct ZX_SPDIF_CLK_RAT define
ASoC: zte: spdif and i2s drivers are not zx296702 specific
ASoC: rsnd: setup BRGCKR/BRRA/BRRB when starting
ASoC: rsnd: enable/disable ADG when suspend/resume timing
ASoC: rsnd: tidyup ssi->usrcnt counter check in hw_params
ALSA: cs46xx: add a new line
ASoC: Intel: update bxt_da7219_max98357a to support quad ch dmic capture
ASoC: nau8825: disable sinc filter for high THD of ADC
ALSA: usb-audio: more tolerant packetsize
ALSA: usb-audio: avoid setting of sample rate multiple times on bus
ASoC: cs35l34: Simplify the logic to set CS35L34_MCLK_CTL setting
ALSA: hda - Gate the mic jack on HP Z1 Gen3 AiO
ALSA: hda: when comparing pin configurations, ignore assoc in addition to seq
...
Diffstat (limited to 'sound/soc/sh/rcar/core.c')
-rw-r--r-- | sound/soc/sh/rcar/core.c | 175 |
1 files changed, 128 insertions, 47 deletions
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c index f18141098b50..4bd68de76130 100644 --- a/sound/soc/sh/rcar/core.c +++ b/sound/soc/sh/rcar/core.c @@ -306,7 +306,7 @@ u32 rsnd_get_adinr_bit(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 *ssi = rsnd_io_to_mod_ssi(io); + struct rsnd_mod *ssiu = rsnd_io_to_mod_ssiu(io); struct rsnd_mod *target; struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io); u32 val = 0x76543210; @@ -315,11 +315,11 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) if (rsnd_io_is_play(io)) { struct rsnd_mod *src = rsnd_io_to_mod_src(io); - target = src ? src : ssi; + target = src ? src : ssiu; } else { struct rsnd_mod *cmd = rsnd_io_to_mod_cmd(io); - target = cmd ? cmd : ssi; + target = cmd ? cmd : ssiu; } mask <<= runtime->channels * 4; @@ -348,32 +348,28 @@ u32 rsnd_get_dalign(struct rsnd_mod *mod, struct rsnd_dai_stream *io) /* * rsnd_dai functions */ -#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 = mod->get_status(io, mod, idx); \ - u32 mask = 0xF << __rsnd_mod_shift_##func; \ - 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; \ - if (add == 0xF) \ - call = 0; \ - else \ - *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), \ - *status, call ? #func : ""); \ - if (call) \ - ret = (mod)->ops->func(mod, io, param); \ - if (ret) \ - dev_dbg(dev, "%s[%d] : rsnd_mod_call error %d\n", \ - rsnd_mod_name(mod), rsnd_mod_id(mod), ret); \ - ret; \ -}) +struct rsnd_mod *rsnd_mod_next(int *iterator, + struct rsnd_dai_stream *io, + enum rsnd_mod_type *array, + int array_size) +{ + struct rsnd_mod *mod; + enum rsnd_mod_type type; + int max = array ? array_size : RSND_MOD_MAX; + + for (; *iterator < max; (*iterator)++) { + type = (array) ? array[*iterator] : *iterator; + mod = io->mod[type]; + if (!mod) + continue; + + (*iterator)++; + + return mod; + } + + return NULL; +} static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { { @@ -409,19 +405,49 @@ static enum rsnd_mod_type rsnd_mod_sequence[][RSND_MOD_MAX] = { }, }; -#define rsnd_dai_call(fn, io, param...) \ -({ \ - struct rsnd_mod *mod; \ - int type, is_play = rsnd_io_is_play(io); \ - int ret = 0, i; \ - for (i = 0; i < RSND_MOD_MAX; i++) { \ - type = rsnd_mod_sequence[is_play][i]; \ - mod = (io)->mod[type]; \ - if (!mod) \ - continue; \ - ret |= rsnd_mod_call(type, io, fn, param); \ - } \ - ret; \ +static int rsnd_status_update(u32 *status, + int shift, int add, int timing) +{ + u32 mask = 0xF << shift; + u8 val = (*status >> shift) & 0xF; + u8 next_val = (val + add) & 0xF; + int func_call = (val == timing); + + if (next_val == 0xF) /* underflow case */ + func_call = 0; + else + *status = (*status & ~mask) + (next_val << shift); + + return func_call; +} + +#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 rsnd_mod *mod; \ + int is_play = rsnd_io_is_play(io); \ + int ret = 0, i; \ + enum rsnd_mod_type *types = rsnd_mod_sequence[is_play]; \ + for_each_rsnd_mod_arrays(i, mod, io, types, RSND_MOD_MAX) { \ + int tmp = 0; \ + u32 *status = mod->get_status(io, mod, types[i]); \ + int func_call = rsnd_status_update(status, \ + __rsnd_mod_shift_##fn, \ + __rsnd_mod_add_##fn, \ + __rsnd_mod_call_##fn); \ + dev_dbg(dev, "%s[%d]\t0x%08x %s\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), *status, \ + (func_call && (mod)->ops->fn) ? #fn : ""); \ + if (func_call && (mod)->ops->fn) \ + tmp = (mod)->ops->fn(mod, io, param); \ + if (tmp) \ + dev_err(dev, "%s[%d] : %s error %d\n", \ + rsnd_mod_name(mod), rsnd_mod_id(mod), \ + #fn, tmp); \ + ret |= tmp; \ + } \ + ret; \ }) int rsnd_dai_connect(struct rsnd_mod *mod, @@ -690,7 +716,33 @@ static int rsnd_soc_set_dai_tdm_slot(struct snd_soc_dai *dai, return 0; } +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_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + return rsnd_dai_call(nolock_start, io, priv); +} + +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_dai_stream *io = rsnd_rdai_to_io(rdai, substream); + + /* + * call rsnd_dai_call without spinlock + */ + rsnd_dai_call(nolock_stop, io, priv); +} + static const struct snd_soc_dai_ops rsnd_soc_dai_ops = { + .startup = rsnd_soc_dai_startup, + .shutdown = rsnd_soc_dai_shutdown, .trigger = rsnd_soc_dai_trigger, .set_fmt = rsnd_soc_dai_set_fmt, .set_tdm_slot = rsnd_soc_set_dai_tdm_slot, @@ -993,7 +1045,11 @@ static int __rsnd_kctrl_new(struct rsnd_mod *mod, void _rsnd_kctrl_remove(struct rsnd_kctrl_cfg *cfg) { - snd_ctl_remove(cfg->card, cfg->kctrl); + if (cfg->card && cfg->kctrl) + snd_ctl_remove(cfg->card, cfg->kctrl); + + cfg->card = NULL; + cfg->kctrl = NULL; } int rsnd_kctrl_new_m(struct rsnd_mod *mod, @@ -1070,8 +1126,8 @@ static int rsnd_pcm_new(struct snd_soc_pcm_runtime *rtd) return snd_pcm_lib_preallocate_pages_for_all( rtd->pcm, - SNDRV_DMA_TYPE_DEV, - rtd->card->snd_card->dev, + SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), PREALLOC_BUFFER, PREALLOC_BUFFER_MAX); } @@ -1092,6 +1148,7 @@ 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); + struct rsnd_mod *mod; int i; /* @@ -1111,8 +1168,8 @@ static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv, * remove all mod from io * and, re connect ssi */ - for (i = 0; i < RSND_MOD_MAX; i++) - rsnd_dai_disconnect((io)->mod[i], io, i); + for_each_rsnd_mod(i, mod, io) + rsnd_dai_disconnect(mod, io, i); rsnd_dai_connect(ssi_mod, io, RSND_MOD_SSI); /* @@ -1251,9 +1308,33 @@ static int rsnd_remove(struct platform_device *pdev) return ret; } +static int rsnd_suspend(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_disable(priv); + + return 0; +} + +static int rsnd_resume(struct device *dev) +{ + struct rsnd_priv *priv = dev_get_drvdata(dev); + + rsnd_adg_clk_enable(priv); + + return 0; +} + +static struct dev_pm_ops rsnd_pm_ops = { + .suspend = rsnd_suspend, + .resume = rsnd_resume, +}; + static struct platform_driver rsnd_driver = { .driver = { .name = "rcar_sound", + .pm = &rsnd_pm_ops, .of_match_table = rsnd_of_match, }, .probe = rsnd_probe, |