diff options
| author | Mark Brown <broonie@linaro.org> | 2014-03-12 19:03:58 -0400 |
|---|---|---|
| committer | Mark Brown <broonie@linaro.org> | 2014-03-12 19:03:58 -0400 |
| commit | da8ab21cfea80655a0f7bbbc3f2fa0975970b8cb (patch) | |
| tree | 66d5a4804f0a15b5dc224bb2de9b0d9cb208eb91 | |
| parent | c6c124225f9551d78a19c291a2e204618f7e1e92 (diff) | |
| parent | 5c1d5f091dc39eecf9a34a8be01492d14c23ad91 (diff) | |
Merge remote-tracking branch 'asoc/topic/core' into asoc-next
| -rw-r--r-- | drivers/base/regmap/regmap.c | 12 | ||||
| -rw-r--r-- | include/linux/regmap.h | 9 | ||||
| -rw-r--r-- | include/sound/soc-dai.h | 1 | ||||
| -rw-r--r-- | include/sound/soc.h | 24 | ||||
| -rw-r--r-- | sound/soc/codecs/adav80x.c | 4 | ||||
| -rw-r--r-- | sound/soc/codecs/tlv320aic23.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/tlv320dac33.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/uda1380.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/wl1273.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8711.c | 2 | ||||
| -rw-r--r-- | sound/soc/codecs/wm8753.c | 4 | ||||
| -rw-r--r-- | sound/soc/soc-cache.c | 13 | ||||
| -rw-r--r-- | sound/soc/soc-compress.c | 65 | ||||
| -rw-r--r-- | sound/soc/soc-core.c | 285 | ||||
| -rw-r--r-- | sound/soc/soc-pcm.c | 109 |
15 files changed, 275 insertions, 261 deletions
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c index 6a19515f8a45..4b2ed0c9e80d 100644 --- a/drivers/base/regmap/regmap.c +++ b/drivers/base/regmap/regmap.c | |||
| @@ -2240,6 +2240,18 @@ int regmap_get_val_bytes(struct regmap *map) | |||
| 2240 | } | 2240 | } |
| 2241 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); | 2241 | EXPORT_SYMBOL_GPL(regmap_get_val_bytes); |
| 2242 | 2242 | ||
| 2243 | int regmap_parse_val(struct regmap *map, const void *buf, | ||
| 2244 | unsigned int *val) | ||
| 2245 | { | ||
| 2246 | if (!map->format.parse_val) | ||
| 2247 | return -EINVAL; | ||
| 2248 | |||
| 2249 | *val = map->format.parse_val(buf); | ||
| 2250 | |||
| 2251 | return 0; | ||
| 2252 | } | ||
| 2253 | EXPORT_SYMBOL_GPL(regmap_parse_val); | ||
| 2254 | |||
| 2243 | static int __init regmap_initcall(void) | 2255 | static int __init regmap_initcall(void) |
| 2244 | { | 2256 | { |
| 2245 | regmap_debugfs_initcall(); | 2257 | regmap_debugfs_initcall(); |
diff --git a/include/linux/regmap.h b/include/linux/regmap.h index 4149f1a9b003..3e1a2e4a92ad 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h | |||
| @@ -423,6 +423,8 @@ bool regmap_check_range_table(struct regmap *map, unsigned int reg, | |||
| 423 | 423 | ||
| 424 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, | 424 | int regmap_register_patch(struct regmap *map, const struct reg_default *regs, |
| 425 | int num_regs); | 425 | int num_regs); |
| 426 | int regmap_parse_val(struct regmap *map, const void *buf, | ||
| 427 | unsigned int *val); | ||
| 426 | 428 | ||
| 427 | static inline bool regmap_reg_in_range(unsigned int reg, | 429 | static inline bool regmap_reg_in_range(unsigned int reg, |
| 428 | const struct regmap_range *range) | 430 | const struct regmap_range *range) |
| @@ -695,6 +697,13 @@ static inline int regmap_register_patch(struct regmap *map, | |||
| 695 | return -EINVAL; | 697 | return -EINVAL; |
| 696 | } | 698 | } |
| 697 | 699 | ||
| 700 | static inline int regmap_parse_val(struct regmap *map, const void *buf, | ||
| 701 | unsigned int *val) | ||
| 702 | { | ||
| 703 | WARN_ONCE(1, "regmap API is disabled"); | ||
| 704 | return -EINVAL; | ||
| 705 | } | ||
| 706 | |||
| 698 | static inline struct regmap *dev_get_regmap(struct device *dev, | 707 | static inline struct regmap *dev_get_regmap(struct device *dev, |
| 699 | const char *name) | 708 | const char *name) |
| 700 | { | 709 | { |
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h index 71f27c403194..8763e539c487 100644 --- a/include/sound/soc-dai.h +++ b/include/sound/soc-dai.h | |||
| @@ -270,6 +270,7 @@ struct snd_soc_dai { | |||
| 270 | /* parent platform/codec */ | 270 | /* parent platform/codec */ |
| 271 | struct snd_soc_platform *platform; | 271 | struct snd_soc_platform *platform; |
| 272 | struct snd_soc_codec *codec; | 272 | struct snd_soc_codec *codec; |
| 273 | struct snd_soc_component *component; | ||
| 273 | 274 | ||
| 274 | struct snd_soc_card *card; | 275 | struct snd_soc_card *card; |
| 275 | 276 | ||
diff --git a/include/sound/soc.h b/include/sound/soc.h index 9a001472b96a..37b470c1e127 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
| @@ -413,6 +413,10 @@ struct snd_pcm_substream *snd_soc_get_dai_substream(struct snd_soc_card *card, | |||
| 413 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, | 413 | struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, |
| 414 | const char *dai_link); | 414 | const char *dai_link); |
| 415 | 415 | ||
| 416 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd); | ||
| 417 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream); | ||
| 418 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream); | ||
| 419 | |||
| 416 | /* Utility functions to get clock rates from various things */ | 420 | /* Utility functions to get clock rates from various things */ |
| 417 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); | 421 | int snd_soc_calc_frame_size(int sample_size, int channels, int tdm_slots); |
| 418 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); | 422 | int snd_soc_params_to_frame_size(struct snd_pcm_hw_params *params); |
| @@ -656,12 +660,19 @@ struct snd_soc_component { | |||
| 656 | const char *name; | 660 | const char *name; |
| 657 | int id; | 661 | int id; |
| 658 | struct device *dev; | 662 | struct device *dev; |
| 663 | |||
| 664 | unsigned int active; | ||
| 665 | |||
| 666 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ | ||
| 667 | |||
| 659 | struct list_head list; | 668 | struct list_head list; |
| 660 | 669 | ||
| 661 | struct snd_soc_dai_driver *dai_drv; | 670 | struct snd_soc_dai_driver *dai_drv; |
| 662 | int num_dai; | 671 | int num_dai; |
| 663 | 672 | ||
| 664 | const struct snd_soc_component_driver *driver; | 673 | const struct snd_soc_component_driver *driver; |
| 674 | |||
| 675 | struct list_head dai_list; | ||
| 665 | }; | 676 | }; |
| 666 | 677 | ||
| 667 | /* SoC Audio Codec device */ | 678 | /* SoC Audio Codec device */ |
| @@ -683,7 +694,6 @@ struct snd_soc_codec { | |||
| 683 | 694 | ||
| 684 | /* runtime */ | 695 | /* runtime */ |
| 685 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ | 696 | struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */ |
| 686 | unsigned int active; | ||
| 687 | unsigned int cache_bypass:1; /* Suppress access to the cache */ | 697 | unsigned int cache_bypass:1; /* Suppress access to the cache */ |
| 688 | unsigned int suspended:1; /* Codec is in suspend PM state */ | 698 | unsigned int suspended:1; /* Codec is in suspend PM state */ |
| 689 | unsigned int probed:1; /* Codec has been probed */ | 699 | unsigned int probed:1; /* Codec has been probed */ |
| @@ -709,7 +719,6 @@ struct snd_soc_codec { | |||
| 709 | 719 | ||
| 710 | /* dapm */ | 720 | /* dapm */ |
| 711 | struct snd_soc_dapm_context dapm; | 721 | struct snd_soc_dapm_context dapm; |
| 712 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ | ||
| 713 | 722 | ||
| 714 | #ifdef CONFIG_DEBUG_FS | 723 | #ifdef CONFIG_DEBUG_FS |
| 715 | struct dentry *debugfs_codec_root; | 724 | struct dentry *debugfs_codec_root; |
| @@ -1168,6 +1177,17 @@ static inline bool snd_soc_volsw_is_stereo(struct soc_mixer_control *mc) | |||
| 1168 | return 1; | 1177 | return 1; |
| 1169 | } | 1178 | } |
| 1170 | 1179 | ||
| 1180 | static inline bool snd_soc_component_is_active( | ||
| 1181 | struct snd_soc_component *component) | ||
| 1182 | { | ||
| 1183 | return component->active != 0; | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | static inline bool snd_soc_codec_is_active(struct snd_soc_codec *codec) | ||
| 1187 | { | ||
| 1188 | return snd_soc_component_is_active(&codec->component); | ||
| 1189 | } | ||
| 1190 | |||
| 1171 | int snd_soc_util_init(void); | 1191 | int snd_soc_util_init(void); |
| 1172 | void snd_soc_util_exit(void); | 1192 | void snd_soc_util_exit(void); |
| 1173 | 1193 | ||
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c index f78b27a7c461..d50cf5b29a27 100644 --- a/sound/soc/codecs/adav80x.c +++ b/sound/soc/codecs/adav80x.c | |||
| @@ -722,7 +722,7 @@ static int adav80x_dai_startup(struct snd_pcm_substream *substream, | |||
| 722 | struct snd_soc_codec *codec = dai->codec; | 722 | struct snd_soc_codec *codec = dai->codec; |
| 723 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 723 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
| 724 | 724 | ||
| 725 | if (!codec->active || !adav80x->rate) | 725 | if (!snd_soc_codec_is_active(codec) || !adav80x->rate) |
| 726 | return 0; | 726 | return 0; |
| 727 | 727 | ||
| 728 | return snd_pcm_hw_constraint_minmax(substream->runtime, | 728 | return snd_pcm_hw_constraint_minmax(substream->runtime, |
| @@ -735,7 +735,7 @@ static void adav80x_dai_shutdown(struct snd_pcm_substream *substream, | |||
| 735 | struct snd_soc_codec *codec = dai->codec; | 735 | struct snd_soc_codec *codec = dai->codec; |
| 736 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); | 736 | struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec); |
| 737 | 737 | ||
| 738 | if (!codec->active) | 738 | if (!snd_soc_codec_is_active(codec)) |
| 739 | adav80x->rate = 0; | 739 | adav80x->rate = 0; |
| 740 | } | 740 | } |
| 741 | 741 | ||
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 5d430cc56f51..458a6aed203e 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c | |||
| @@ -400,7 +400,7 @@ static void tlv320aic23_shutdown(struct snd_pcm_substream *substream, | |||
| 400 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); | 400 | struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec); |
| 401 | 401 | ||
| 402 | /* deactivate */ | 402 | /* deactivate */ |
| 403 | if (!codec->active) { | 403 | if (!snd_soc_codec_is_active(codec)) { |
| 404 | udelay(50); | 404 | udelay(50); |
| 405 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); | 405 | snd_soc_write(codec, TLV320AIC23_ACTIVE, 0x0); |
| 406 | } | 406 | } |
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index 4f358393d6d6..35b2d244e42e 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c | |||
| @@ -461,7 +461,7 @@ static int dac33_set_fifo_mode(struct snd_kcontrol *kcontrol, | |||
| 461 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) | 461 | if (dac33->fifo_mode == ucontrol->value.integer.value[0]) |
| 462 | return 0; | 462 | return 0; |
| 463 | /* Do not allow changes while stream is running*/ | 463 | /* Do not allow changes while stream is running*/ |
| 464 | if (codec->active) | 464 | if (snd_soc_codec_is_active(codec)) |
| 465 | return -EPERM; | 465 | return -EPERM; |
| 466 | 466 | ||
| 467 | if (ucontrol->value.integer.value[0] < 0 || | 467 | if (ucontrol->value.integer.value[0] < 0 || |
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index 726df6d43c2b..8e3940dcff20 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c | |||
| @@ -108,7 +108,7 @@ static int uda1380_write(struct snd_soc_codec *codec, unsigned int reg, | |||
| 108 | /* the interpolator & decimator regs must only be written when the | 108 | /* the interpolator & decimator regs must only be written when the |
| 109 | * codec DAI is active. | 109 | * codec DAI is active. |
| 110 | */ | 110 | */ |
| 111 | if (!codec->active && (reg >= UDA1380_MVOL)) | 111 | if (!snd_soc_codec_is_active(codec) && (reg >= UDA1380_MVOL)) |
| 112 | return 0; | 112 | return 0; |
| 113 | pr_debug("uda1380: hw write %x val %x\n", reg, value); | 113 | pr_debug("uda1380: hw write %x val %x\n", reg, value); |
| 114 | if (codec->hw_write(codec->control_data, data, 3) == 3) { | 114 | if (codec->hw_write(codec->control_data, data, 3) == 3) { |
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c index b7ab2ef567c8..47e96ff30064 100644 --- a/sound/soc/codecs/wl1273.c +++ b/sound/soc/codecs/wl1273.c | |||
| @@ -197,7 +197,7 @@ static int snd_wl1273_set_audio_route(struct snd_kcontrol *kcontrol, | |||
| 197 | return 0; | 197 | return 0; |
| 198 | 198 | ||
| 199 | /* Do not allow changes while stream is running */ | 199 | /* Do not allow changes while stream is running */ |
| 200 | if (codec->active) | 200 | if (snd_soc_codec_is_active(codec)) |
| 201 | return -EPERM; | 201 | return -EPERM; |
| 202 | 202 | ||
| 203 | if (ucontrol->value.integer.value[0] < 0 || | 203 | if (ucontrol->value.integer.value[0] < 0 || |
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c index d99f948c513c..6efcc40a7cb3 100644 --- a/sound/soc/codecs/wm8711.c +++ b/sound/soc/codecs/wm8711.c | |||
| @@ -201,7 +201,7 @@ static void wm8711_shutdown(struct snd_pcm_substream *substream, | |||
| 201 | struct snd_soc_codec *codec = dai->codec; | 201 | struct snd_soc_codec *codec = dai->codec; |
| 202 | 202 | ||
| 203 | /* deactivate */ | 203 | /* deactivate */ |
| 204 | if (!codec->active) { | 204 | if (!snd_soc_codec_is_active(codec)) { |
| 205 | udelay(50); | 205 | udelay(50); |
| 206 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); | 206 | snd_soc_write(codec, WM8711_ACTIVE, 0x0); |
| 207 | } | 207 | } |
diff --git a/sound/soc/codecs/wm8753.c b/sound/soc/codecs/wm8753.c index be85da93a268..5cf4bebc5d89 100644 --- a/sound/soc/codecs/wm8753.c +++ b/sound/soc/codecs/wm8753.c | |||
| @@ -251,7 +251,7 @@ static int wm8753_set_dai(struct snd_kcontrol *kcontrol, | |||
| 251 | if (wm8753->dai_func == ucontrol->value.integer.value[0]) | 251 | if (wm8753->dai_func == ucontrol->value.integer.value[0]) |
| 252 | return 0; | 252 | return 0; |
| 253 | 253 | ||
| 254 | if (codec->active) | 254 | if (snd_soc_codec_is_active(codec)) |
| 255 | return -EBUSY; | 255 | return -EBUSY; |
| 256 | 256 | ||
| 257 | ioctl = snd_soc_read(codec, WM8753_IOCTL); | 257 | ioctl = snd_soc_read(codec, WM8753_IOCTL); |
| @@ -1314,7 +1314,7 @@ static int wm8753_mute(struct snd_soc_dai *dai, int mute) | |||
| 1314 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. | 1314 | /* the digital mute covers the HiFi and Voice DAC's on the WM8753. |
| 1315 | * make sure we check if they are not both active when we mute */ | 1315 | * make sure we check if they are not both active when we mute */ |
| 1316 | if (mute && wm8753->dai_func == 1) { | 1316 | if (mute && wm8753->dai_func == 1) { |
| 1317 | if (!codec->active) | 1317 | if (!snd_soc_codec_is_active(codec)) |
| 1318 | snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); | 1318 | snd_soc_write(codec, WM8753_DAC, mute_reg | 0x8); |
| 1319 | } else { | 1319 | } else { |
| 1320 | if (mute) | 1320 | if (mute) |
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c index 375dc6dfba4e..bfed3e4c45ff 100644 --- a/sound/soc/soc-cache.c +++ b/sound/soc/soc-cache.c | |||
| @@ -96,8 +96,7 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec) | |||
| 96 | { | 96 | { |
| 97 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", | 97 | dev_dbg(codec->dev, "ASoC: Destroying cache for %s codec\n", |
| 98 | codec->name); | 98 | codec->name); |
| 99 | if (!codec->reg_cache) | 99 | |
| 100 | return 0; | ||
| 101 | kfree(codec->reg_cache); | 100 | kfree(codec->reg_cache); |
| 102 | codec->reg_cache = NULL; | 101 | codec->reg_cache = NULL; |
| 103 | return 0; | 102 | return 0; |
| @@ -117,8 +116,9 @@ int snd_soc_cache_read(struct snd_soc_codec *codec, | |||
| 117 | return -EINVAL; | 116 | return -EINVAL; |
| 118 | 117 | ||
| 119 | mutex_lock(&codec->cache_rw_mutex); | 118 | mutex_lock(&codec->cache_rw_mutex); |
| 120 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, | 119 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) |
| 121 | codec->driver->reg_word_size); | 120 | *value = snd_soc_get_cache_val(codec->reg_cache, reg, |
| 121 | codec->driver->reg_word_size); | ||
| 122 | mutex_unlock(&codec->cache_rw_mutex); | 122 | mutex_unlock(&codec->cache_rw_mutex); |
| 123 | 123 | ||
| 124 | return 0; | 124 | return 0; |
| @@ -136,8 +136,9 @@ int snd_soc_cache_write(struct snd_soc_codec *codec, | |||
| 136 | unsigned int reg, unsigned int value) | 136 | unsigned int reg, unsigned int value) |
| 137 | { | 137 | { |
| 138 | mutex_lock(&codec->cache_rw_mutex); | 138 | mutex_lock(&codec->cache_rw_mutex); |
| 139 | snd_soc_set_cache_val(codec->reg_cache, reg, value, | 139 | if (!ZERO_OR_NULL_PTR(codec->reg_cache)) |
| 140 | codec->driver->reg_word_size); | 140 | snd_soc_set_cache_val(codec->reg_cache, reg, value, |
| 141 | codec->driver->reg_word_size); | ||
| 141 | mutex_unlock(&codec->cache_rw_mutex); | 142 | mutex_unlock(&codec->cache_rw_mutex); |
| 142 | 143 | ||
| 143 | return 0; | 144 | return 0; |
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c index 5e9690c85d8f..91083e6a6b38 100644 --- a/sound/soc/soc-compress.c +++ b/sound/soc/soc-compress.c | |||
| @@ -30,8 +30,6 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
| 30 | { | 30 | { |
| 31 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; | 31 | struct snd_soc_pcm_runtime *rtd = cstream->private_data; |
| 32 | struct snd_soc_platform *platform = rtd->platform; | 32 | struct snd_soc_platform *platform = rtd->platform; |
| 33 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
| 34 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 35 | int ret = 0; | 33 | int ret = 0; |
| 36 | 34 | ||
| 37 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 35 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
| @@ -52,17 +50,7 @@ static int soc_compr_open(struct snd_compr_stream *cstream) | |||
| 52 | } | 50 | } |
| 53 | } | 51 | } |
| 54 | 52 | ||
| 55 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 53 | snd_soc_runtime_activate(rtd, cstream->direction); |
| 56 | cpu_dai->playback_active++; | ||
| 57 | codec_dai->playback_active++; | ||
| 58 | } else { | ||
| 59 | cpu_dai->capture_active++; | ||
| 60 | codec_dai->capture_active++; | ||
| 61 | } | ||
| 62 | |||
| 63 | cpu_dai->active++; | ||
| 64 | codec_dai->active++; | ||
| 65 | rtd->codec->active++; | ||
| 66 | 54 | ||
| 67 | mutex_unlock(&rtd->pcm_mutex); | 55 | mutex_unlock(&rtd->pcm_mutex); |
| 68 | 56 | ||
| @@ -81,8 +69,6 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
| 81 | struct snd_soc_pcm_runtime *fe = cstream->private_data; | 69 | struct snd_soc_pcm_runtime *fe = cstream->private_data; |
| 82 | struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; | 70 | struct snd_pcm_substream *fe_substream = fe->pcm->streams[0].substream; |
| 83 | struct snd_soc_platform *platform = fe->platform; | 71 | struct snd_soc_platform *platform = fe->platform; |
| 84 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
| 85 | struct snd_soc_dai *codec_dai = fe->codec_dai; | ||
| 86 | struct snd_soc_dpcm *dpcm; | 72 | struct snd_soc_dpcm *dpcm; |
| 87 | struct snd_soc_dapm_widget_list *list; | 73 | struct snd_soc_dapm_widget_list *list; |
| 88 | int stream; | 74 | int stream; |
| @@ -140,17 +126,7 @@ static int soc_compr_open_fe(struct snd_compr_stream *cstream) | |||
| 140 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; | 126 | fe->dpcm[stream].state = SND_SOC_DPCM_STATE_OPEN; |
| 141 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; | 127 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO; |
| 142 | 128 | ||
| 143 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 129 | snd_soc_runtime_activate(fe, stream); |
| 144 | cpu_dai->playback_active++; | ||
| 145 | codec_dai->playback_active++; | ||
| 146 | } else { | ||
| 147 | cpu_dai->capture_active++; | ||
| 148 | codec_dai->capture_active++; | ||
| 149 | } | ||
| 150 | |||
| 151 | cpu_dai->active++; | ||
| 152 | codec_dai->active++; | ||
| 153 | fe->codec->active++; | ||
| 154 | 130 | ||
| 155 | mutex_unlock(&fe->card->mutex); | 131 | mutex_unlock(&fe->card->mutex); |
| 156 | 132 | ||
| @@ -202,23 +178,18 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
| 202 | struct snd_soc_platform *platform = rtd->platform; | 178 | struct snd_soc_platform *platform = rtd->platform; |
| 203 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 179 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 204 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 180 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 205 | struct snd_soc_codec *codec = rtd->codec; | 181 | int stream; |
| 206 | 182 | ||
| 207 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 183 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
| 208 | 184 | ||
| 209 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 185 | if (cstream->direction == SND_COMPRESS_PLAYBACK) |
| 210 | cpu_dai->playback_active--; | 186 | stream = SNDRV_PCM_STREAM_PLAYBACK; |
| 211 | codec_dai->playback_active--; | 187 | else |
| 212 | } else { | 188 | stream = SNDRV_PCM_STREAM_CAPTURE; |
| 213 | cpu_dai->capture_active--; | ||
| 214 | codec_dai->capture_active--; | ||
| 215 | } | ||
| 216 | 189 | ||
| 217 | snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); | 190 | snd_soc_runtime_deactivate(rtd, stream); |
| 218 | 191 | ||
| 219 | cpu_dai->active--; | 192 | snd_soc_dai_digital_mute(codec_dai, 1, cstream->direction); |
| 220 | codec_dai->active--; | ||
| 221 | codec->active--; | ||
| 222 | 193 | ||
| 223 | if (!cpu_dai->active) | 194 | if (!cpu_dai->active) |
| 224 | cpu_dai->rate = 0; | 195 | cpu_dai->rate = 0; |
| @@ -235,8 +206,7 @@ static int soc_compr_free(struct snd_compr_stream *cstream) | |||
| 235 | cpu_dai->runtime = NULL; | 206 | cpu_dai->runtime = NULL; |
| 236 | 207 | ||
| 237 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 208 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { |
| 238 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 209 | if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
| 239 | rtd->dai_link->ignore_pmdown_time) { | ||
| 240 | snd_soc_dapm_stream_event(rtd, | 210 | snd_soc_dapm_stream_event(rtd, |
| 241 | SNDRV_PCM_STREAM_PLAYBACK, | 211 | SNDRV_PCM_STREAM_PLAYBACK, |
| 242 | SND_SOC_DAPM_STREAM_STOP); | 212 | SND_SOC_DAPM_STREAM_STOP); |
| @@ -261,26 +231,17 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream) | |||
| 261 | { | 231 | { |
| 262 | struct snd_soc_pcm_runtime *fe = cstream->private_data; | 232 | struct snd_soc_pcm_runtime *fe = cstream->private_data; |
| 263 | struct snd_soc_platform *platform = fe->platform; | 233 | struct snd_soc_platform *platform = fe->platform; |
| 264 | struct snd_soc_dai *cpu_dai = fe->cpu_dai; | ||
| 265 | struct snd_soc_dai *codec_dai = fe->codec_dai; | ||
| 266 | struct snd_soc_dpcm *dpcm; | 234 | struct snd_soc_dpcm *dpcm; |
| 267 | int stream, ret; | 235 | int stream, ret; |
| 268 | 236 | ||
| 269 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); | 237 | mutex_lock_nested(&fe->card->mutex, SND_SOC_CARD_CLASS_RUNTIME); |
| 270 | 238 | ||
| 271 | if (cstream->direction == SND_COMPRESS_PLAYBACK) { | 239 | if (cstream->direction == SND_COMPRESS_PLAYBACK) |
| 272 | stream = SNDRV_PCM_STREAM_PLAYBACK; | 240 | stream = SNDRV_PCM_STREAM_PLAYBACK; |
| 273 | cpu_dai->playback_active--; | 241 | else |
| 274 | codec_dai->playback_active--; | ||
| 275 | } else { | ||
| 276 | stream = SNDRV_PCM_STREAM_CAPTURE; | 242 | stream = SNDRV_PCM_STREAM_CAPTURE; |
| 277 | cpu_dai->capture_active--; | ||
| 278 | codec_dai->capture_active--; | ||
| 279 | } | ||
| 280 | 243 | ||
| 281 | cpu_dai->active--; | 244 | snd_soc_runtime_deactivate(fe, stream); |
| 282 | codec_dai->active--; | ||
| 283 | fe->codec->active--; | ||
| 284 | 245 | ||
| 285 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; | 246 | fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_FE; |
| 286 | 247 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fe1df50805a3..a78bba4d52fb 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
| @@ -56,7 +56,6 @@ EXPORT_SYMBOL_GPL(snd_soc_debugfs_root); | |||
| 56 | #endif | 56 | #endif |
| 57 | 57 | ||
| 58 | static DEFINE_MUTEX(client_mutex); | 58 | static DEFINE_MUTEX(client_mutex); |
| 59 | static LIST_HEAD(dai_list); | ||
| 60 | static LIST_HEAD(platform_list); | 59 | static LIST_HEAD(platform_list); |
| 61 | static LIST_HEAD(codec_list); | 60 | static LIST_HEAD(codec_list); |
| 62 | static LIST_HEAD(component_list); | 61 | static LIST_HEAD(component_list); |
| @@ -370,18 +369,22 @@ static ssize_t dai_list_read_file(struct file *file, char __user *user_buf, | |||
| 370 | { | 369 | { |
| 371 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); | 370 | char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); |
| 372 | ssize_t len, ret = 0; | 371 | ssize_t len, ret = 0; |
| 372 | struct snd_soc_component *component; | ||
| 373 | struct snd_soc_dai *dai; | 373 | struct snd_soc_dai *dai; |
| 374 | 374 | ||
| 375 | if (!buf) | 375 | if (!buf) |
| 376 | return -ENOMEM; | 376 | return -ENOMEM; |
| 377 | 377 | ||
| 378 | list_for_each_entry(dai, &dai_list, list) { | 378 | list_for_each_entry(component, &component_list, list) { |
| 379 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", dai->name); | 379 | list_for_each_entry(dai, &component->dai_list, list) { |
| 380 | if (len >= 0) | 380 | len = snprintf(buf + ret, PAGE_SIZE - ret, "%s\n", |
| 381 | ret += len; | 381 | dai->name); |
| 382 | if (ret > PAGE_SIZE) { | 382 | if (len >= 0) |
| 383 | ret = PAGE_SIZE; | 383 | ret += len; |
| 384 | break; | 384 | if (ret > PAGE_SIZE) { |
| 385 | ret = PAGE_SIZE; | ||
| 386 | break; | ||
| 387 | } | ||
| 385 | } | 388 | } |
| 386 | } | 389 | } |
| 387 | 390 | ||
| @@ -855,6 +858,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
| 855 | { | 858 | { |
| 856 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; | 859 | struct snd_soc_dai_link *dai_link = &card->dai_link[num]; |
| 857 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; | 860 | struct snd_soc_pcm_runtime *rtd = &card->rtd[num]; |
| 861 | struct snd_soc_component *component; | ||
| 858 | struct snd_soc_codec *codec; | 862 | struct snd_soc_codec *codec; |
| 859 | struct snd_soc_platform *platform; | 863 | struct snd_soc_platform *platform; |
| 860 | struct snd_soc_dai *codec_dai, *cpu_dai; | 864 | struct snd_soc_dai *codec_dai, *cpu_dai; |
| @@ -863,18 +867,20 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
| 863 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); | 867 | dev_dbg(card->dev, "ASoC: binding %s at idx %d\n", dai_link->name, num); |
| 864 | 868 | ||
| 865 | /* Find CPU DAI from registered DAIs*/ | 869 | /* Find CPU DAI from registered DAIs*/ |
| 866 | list_for_each_entry(cpu_dai, &dai_list, list) { | 870 | list_for_each_entry(component, &component_list, list) { |
| 867 | if (dai_link->cpu_of_node && | 871 | if (dai_link->cpu_of_node && |
| 868 | (cpu_dai->dev->of_node != dai_link->cpu_of_node)) | 872 | component->dev->of_node != dai_link->cpu_of_node) |
| 869 | continue; | 873 | continue; |
| 870 | if (dai_link->cpu_name && | 874 | if (dai_link->cpu_name && |
| 871 | strcmp(dev_name(cpu_dai->dev), dai_link->cpu_name)) | 875 | strcmp(dev_name(component->dev), dai_link->cpu_name)) |
| 872 | continue; | ||
| 873 | if (dai_link->cpu_dai_name && | ||
| 874 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
| 875 | continue; | 876 | continue; |
| 877 | list_for_each_entry(cpu_dai, &component->dai_list, list) { | ||
| 878 | if (dai_link->cpu_dai_name && | ||
| 879 | strcmp(cpu_dai->name, dai_link->cpu_dai_name)) | ||
| 880 | continue; | ||
| 876 | 881 | ||
| 877 | rtd->cpu_dai = cpu_dai; | 882 | rtd->cpu_dai = cpu_dai; |
| 883 | } | ||
| 878 | } | 884 | } |
| 879 | 885 | ||
| 880 | if (!rtd->cpu_dai) { | 886 | if (!rtd->cpu_dai) { |
| @@ -899,12 +905,10 @@ static int soc_bind_dai_link(struct snd_soc_card *card, int num) | |||
| 899 | * CODEC found, so find CODEC DAI from registered DAIs from | 905 | * CODEC found, so find CODEC DAI from registered DAIs from |
| 900 | * this CODEC | 906 | * this CODEC |
| 901 | */ | 907 | */ |
| 902 | list_for_each_entry(codec_dai, &dai_list, list) { | 908 | list_for_each_entry(codec_dai, &codec->component.dai_list, list) { |
| 903 | if (codec->dev == codec_dai->dev && | 909 | if (!strcmp(codec_dai->name, dai_link->codec_dai_name)) { |
| 904 | !strcmp(codec_dai->name, | ||
| 905 | dai_link->codec_dai_name)) { | ||
| 906 | |||
| 907 | rtd->codec_dai = codec_dai; | 910 | rtd->codec_dai = codec_dai; |
| 911 | break; | ||
| 908 | } | 912 | } |
| 909 | } | 913 | } |
| 910 | 914 | ||
| @@ -1128,12 +1132,8 @@ static int soc_probe_codec(struct snd_soc_card *card, | |||
| 1128 | driver->num_dapm_widgets); | 1132 | driver->num_dapm_widgets); |
| 1129 | 1133 | ||
| 1130 | /* Create DAPM widgets for each DAI stream */ | 1134 | /* Create DAPM widgets for each DAI stream */ |
| 1131 | list_for_each_entry(dai, &dai_list, list) { | 1135 | list_for_each_entry(dai, &codec->component.dai_list, list) |
| 1132 | if (dai->dev != codec->dev) | ||
| 1133 | continue; | ||
| 1134 | |||
| 1135 | snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); | 1136 | snd_soc_dapm_new_dai_widgets(&codec->dapm, dai); |
| 1136 | } | ||
| 1137 | 1137 | ||
| 1138 | codec->dapm.idle_bias_off = driver->idle_bias_off; | 1138 | codec->dapm.idle_bias_off = driver->idle_bias_off; |
| 1139 | 1139 | ||
| @@ -1180,6 +1180,7 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
| 1180 | { | 1180 | { |
| 1181 | int ret = 0; | 1181 | int ret = 0; |
| 1182 | const struct snd_soc_platform_driver *driver = platform->driver; | 1182 | const struct snd_soc_platform_driver *driver = platform->driver; |
| 1183 | struct snd_soc_component *component; | ||
| 1183 | struct snd_soc_dai *dai; | 1184 | struct snd_soc_dai *dai; |
| 1184 | 1185 | ||
| 1185 | platform->card = card; | 1186 | platform->card = card; |
| @@ -1195,11 +1196,11 @@ static int soc_probe_platform(struct snd_soc_card *card, | |||
| 1195 | driver->dapm_widgets, driver->num_dapm_widgets); | 1196 | driver->dapm_widgets, driver->num_dapm_widgets); |
| 1196 | 1197 | ||
| 1197 | /* Create DAPM widgets for each DAI stream */ | 1198 | /* Create DAPM widgets for each DAI stream */ |
| 1198 | list_for_each_entry(dai, &dai_list, list) { | 1199 | list_for_each_entry(component, &component_list, list) { |
| 1199 | if (dai->dev != platform->dev) | 1200 | if (component->dev != platform->dev) |
| 1200 | continue; | 1201 | continue; |
| 1201 | 1202 | list_for_each_entry(dai, &component->dai_list, list) | |
| 1202 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); | 1203 | snd_soc_dapm_new_dai_widgets(&platform->dapm, dai); |
| 1203 | } | 1204 | } |
| 1204 | 1205 | ||
| 1205 | platform->dapm.idle_bias_off = 1; | 1206 | platform->dapm.idle_bias_off = 1; |
| @@ -2818,7 +2819,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
| 2818 | unsigned int mask = (1 << fls(max)) - 1; | 2819 | unsigned int mask = (1 << fls(max)) - 1; |
| 2819 | unsigned int invert = mc->invert; | 2820 | unsigned int invert = mc->invert; |
| 2820 | int err; | 2821 | int err; |
| 2821 | bool type_2r = 0; | 2822 | bool type_2r = false; |
| 2822 | unsigned int val2 = 0; | 2823 | unsigned int val2 = 0; |
| 2823 | unsigned int val, val_mask; | 2824 | unsigned int val, val_mask; |
| 2824 | 2825 | ||
| @@ -2836,7 +2837,7 @@ int snd_soc_put_volsw(struct snd_kcontrol *kcontrol, | |||
| 2836 | val |= val2 << rshift; | 2837 | val |= val2 << rshift; |
| 2837 | } else { | 2838 | } else { |
| 2838 | val2 = val2 << shift; | 2839 | val2 = val2 << shift; |
| 2839 | type_2r = 1; | 2840 | type_2r = true; |
| 2840 | } | 2841 | } |
| 2841 | } | 2842 | } |
| 2842 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); | 2843 | err = snd_soc_update_bits_locked(codec, reg, val_mask, val); |
| @@ -3234,7 +3235,7 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
| 3234 | struct soc_bytes *params = (void *)kcontrol->private_value; | 3235 | struct soc_bytes *params = (void *)kcontrol->private_value; |
| 3235 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); | 3236 | struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol); |
| 3236 | int ret, len; | 3237 | int ret, len; |
| 3237 | unsigned int val; | 3238 | unsigned int val, mask; |
| 3238 | void *data; | 3239 | void *data; |
| 3239 | 3240 | ||
| 3240 | if (!codec->using_regmap) | 3241 | if (!codec->using_regmap) |
| @@ -3264,12 +3265,36 @@ int snd_soc_bytes_put(struct snd_kcontrol *kcontrol, | |||
| 3264 | ((u8 *)data)[0] |= val; | 3265 | ((u8 *)data)[0] |= val; |
| 3265 | break; | 3266 | break; |
| 3266 | case 2: | 3267 | case 2: |
| 3267 | ((u16 *)data)[0] &= cpu_to_be16(~params->mask); | 3268 | mask = ~params->mask; |
| 3268 | ((u16 *)data)[0] |= cpu_to_be16(val); | 3269 | ret = regmap_parse_val(codec->control_data, |
| 3270 | &mask, &mask); | ||
| 3271 | if (ret != 0) | ||
| 3272 | goto out; | ||
| 3273 | |||
| 3274 | ((u16 *)data)[0] &= mask; | ||
| 3275 | |||
| 3276 | ret = regmap_parse_val(codec->control_data, | ||
| 3277 | &val, &val); | ||
| 3278 | if (ret != 0) | ||
| 3279 | goto out; | ||
| 3280 | |||
| 3281 | ((u16 *)data)[0] |= val; | ||
| 3269 | break; | 3282 | break; |
| 3270 | case 4: | 3283 | case 4: |
| 3271 | ((u32 *)data)[0] &= cpu_to_be32(~params->mask); | 3284 | mask = ~params->mask; |
| 3272 | ((u32 *)data)[0] |= cpu_to_be32(val); | 3285 | ret = regmap_parse_val(codec->control_data, |
| 3286 | &mask, &mask); | ||
| 3287 | if (ret != 0) | ||
| 3288 | goto out; | ||
| 3289 | |||
| 3290 | ((u32 *)data)[0] &= mask; | ||
| 3291 | |||
| 3292 | ret = regmap_parse_val(codec->control_data, | ||
| 3293 | &val, &val); | ||
| 3294 | if (ret != 0) | ||
| 3295 | goto out; | ||
| 3296 | |||
| 3297 | ((u32 *)data)[0] |= val; | ||
| 3273 | break; | 3298 | break; |
| 3274 | default: | 3299 | default: |
| 3275 | ret = -EINVAL; | 3300 | ret = -EINVAL; |
| @@ -3626,7 +3651,7 @@ int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, | |||
| 3626 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, | 3651 | return dai->driver->ops->set_tdm_slot(dai, tx_mask, rx_mask, |
| 3627 | slots, slot_width); | 3652 | slots, slot_width); |
| 3628 | else | 3653 | else |
| 3629 | return -EINVAL; | 3654 | return -ENOTSUPP; |
| 3630 | } | 3655 | } |
| 3631 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); | 3656 | EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); |
| 3632 | 3657 | ||
| @@ -3882,95 +3907,42 @@ static inline char *fmt_multiple_name(struct device *dev, | |||
| 3882 | } | 3907 | } |
| 3883 | 3908 | ||
| 3884 | /** | 3909 | /** |
| 3885 | * snd_soc_register_dai - Register a DAI with the ASoC core | 3910 | * snd_soc_unregister_dai - Unregister DAIs from the ASoC core |
| 3886 | * | 3911 | * |
| 3887 | * @dai: DAI to register | 3912 | * @component: The component for which the DAIs should be unregistered |
| 3888 | */ | 3913 | */ |
| 3889 | static int snd_soc_register_dai(struct device *dev, | 3914 | static void snd_soc_unregister_dais(struct snd_soc_component *component) |
| 3890 | struct snd_soc_dai_driver *dai_drv) | ||
| 3891 | { | 3915 | { |
| 3892 | struct snd_soc_codec *codec; | 3916 | struct snd_soc_dai *dai, *_dai; |
| 3893 | struct snd_soc_dai *dai; | ||
| 3894 | |||
| 3895 | dev_dbg(dev, "ASoC: dai register %s\n", dev_name(dev)); | ||
| 3896 | 3917 | ||
| 3897 | dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL); | 3918 | list_for_each_entry_safe(dai, _dai, &component->dai_list, list) { |
| 3898 | if (dai == NULL) | 3919 | dev_dbg(component->dev, "ASoC: Unregistered DAI '%s'\n", |
| 3899 | return -ENOMEM; | 3920 | dai->name); |
| 3900 | 3921 | list_del(&dai->list); | |
| 3901 | /* create DAI component name */ | 3922 | kfree(dai->name); |
| 3902 | dai->name = fmt_single_name(dev, &dai->id); | ||
| 3903 | if (dai->name == NULL) { | ||
| 3904 | kfree(dai); | 3923 | kfree(dai); |
| 3905 | return -ENOMEM; | ||
| 3906 | } | ||
| 3907 | |||
| 3908 | dai->dev = dev; | ||
| 3909 | dai->driver = dai_drv; | ||
| 3910 | dai->dapm.dev = dev; | ||
| 3911 | if (!dai->driver->ops) | ||
| 3912 | dai->driver->ops = &null_dai_ops; | ||
| 3913 | |||
| 3914 | mutex_lock(&client_mutex); | ||
| 3915 | |||
| 3916 | list_for_each_entry(codec, &codec_list, list) { | ||
| 3917 | if (codec->dev == dev) { | ||
| 3918 | dev_dbg(dev, "ASoC: Mapped DAI %s to CODEC %s\n", | ||
| 3919 | dai->name, codec->name); | ||
| 3920 | dai->codec = codec; | ||
| 3921 | break; | ||
| 3922 | } | ||
| 3923 | } | ||
| 3924 | |||
| 3925 | if (!dai->codec) | ||
| 3926 | dai->dapm.idle_bias_off = 1; | ||
| 3927 | |||
| 3928 | list_add(&dai->list, &dai_list); | ||
| 3929 | |||
| 3930 | mutex_unlock(&client_mutex); | ||
| 3931 | |||
| 3932 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); | ||
| 3933 | |||
| 3934 | return 0; | ||
| 3935 | } | ||
| 3936 | |||
| 3937 | /** | ||
| 3938 | * snd_soc_unregister_dai - Unregister a DAI from the ASoC core | ||
| 3939 | * | ||
| 3940 | * @dai: DAI to unregister | ||
| 3941 | */ | ||
| 3942 | static void snd_soc_unregister_dai(struct device *dev) | ||
| 3943 | { | ||
| 3944 | struct snd_soc_dai *dai; | ||
| 3945 | |||
| 3946 | list_for_each_entry(dai, &dai_list, list) { | ||
| 3947 | if (dev == dai->dev) | ||
| 3948 | goto found; | ||
| 3949 | } | 3924 | } |
| 3950 | return; | ||
| 3951 | |||
| 3952 | found: | ||
| 3953 | mutex_lock(&client_mutex); | ||
| 3954 | list_del(&dai->list); | ||
| 3955 | mutex_unlock(&client_mutex); | ||
| 3956 | |||
| 3957 | dev_dbg(dev, "ASoC: Unregistered DAI '%s'\n", dai->name); | ||
| 3958 | kfree(dai->name); | ||
| 3959 | kfree(dai); | ||
| 3960 | } | 3925 | } |
| 3961 | 3926 | ||
| 3962 | /** | 3927 | /** |
| 3963 | * snd_soc_register_dais - Register multiple DAIs with the ASoC core | 3928 | * snd_soc_register_dais - Register a DAI with the ASoC core |
| 3964 | * | 3929 | * |
| 3965 | * @dai: Array of DAIs to register | 3930 | * @component: The component the DAIs are registered for |
| 3931 | * @codec: The CODEC that the DAIs are registered for, NULL if the component is | ||
| 3932 | * not a CODEC. | ||
| 3933 | * @dai_drv: DAI driver to use for the DAIs | ||
| 3966 | * @count: Number of DAIs | 3934 | * @count: Number of DAIs |
| 3935 | * @legacy_dai_naming: Use the legacy naming scheme and let the DAI inherit the | ||
| 3936 | * parent's name. | ||
| 3967 | */ | 3937 | */ |
| 3968 | static int snd_soc_register_dais(struct device *dev, | 3938 | static int snd_soc_register_dais(struct snd_soc_component *component, |
| 3969 | struct snd_soc_dai_driver *dai_drv, size_t count) | 3939 | struct snd_soc_codec *codec, struct snd_soc_dai_driver *dai_drv, |
| 3940 | size_t count, bool legacy_dai_naming) | ||
| 3970 | { | 3941 | { |
| 3971 | struct snd_soc_codec *codec; | 3942 | struct device *dev = component->dev; |
| 3972 | struct snd_soc_dai *dai; | 3943 | struct snd_soc_dai *dai; |
| 3973 | int i, ret = 0; | 3944 | unsigned int i; |
| 3945 | int ret; | ||
| 3974 | 3946 | ||
| 3975 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); | 3947 | dev_dbg(dev, "ASoC: dai register %s #%Zu\n", dev_name(dev), count); |
| 3976 | 3948 | ||
| @@ -3982,70 +3954,54 @@ static int snd_soc_register_dais(struct device *dev, | |||
| 3982 | goto err; | 3954 | goto err; |
| 3983 | } | 3955 | } |
| 3984 | 3956 | ||
| 3985 | /* create DAI component name */ | 3957 | /* |
| 3986 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | 3958 | * Back in the old days when we still had component-less DAIs, |
| 3959 | * instead of having a static name, component-less DAIs would | ||
| 3960 | * inherit the name of the parent device so it is possible to | ||
| 3961 | * register multiple instances of the DAI. We still need to keep | ||
| 3962 | * the same naming style even though those DAIs are not | ||
| 3963 | * component-less anymore. | ||
| 3964 | */ | ||
| 3965 | if (count == 1 && legacy_dai_naming) { | ||
| 3966 | dai->name = fmt_single_name(dev, &dai->id); | ||
| 3967 | } else { | ||
| 3968 | dai->name = fmt_multiple_name(dev, &dai_drv[i]); | ||
| 3969 | if (dai_drv[i].id) | ||
| 3970 | dai->id = dai_drv[i].id; | ||
| 3971 | else | ||
| 3972 | dai->id = i; | ||
| 3973 | } | ||
| 3987 | if (dai->name == NULL) { | 3974 | if (dai->name == NULL) { |
| 3988 | kfree(dai); | 3975 | kfree(dai); |
| 3989 | ret = -EINVAL; | 3976 | ret = -ENOMEM; |
| 3990 | goto err; | 3977 | goto err; |
| 3991 | } | 3978 | } |
| 3992 | 3979 | ||
| 3980 | dai->component = component; | ||
| 3981 | dai->codec = codec; | ||
| 3993 | dai->dev = dev; | 3982 | dai->dev = dev; |
| 3994 | dai->driver = &dai_drv[i]; | 3983 | dai->driver = &dai_drv[i]; |
| 3995 | if (dai->driver->id) | ||
| 3996 | dai->id = dai->driver->id; | ||
| 3997 | else | ||
| 3998 | dai->id = i; | ||
| 3999 | dai->dapm.dev = dev; | 3984 | dai->dapm.dev = dev; |
| 4000 | if (!dai->driver->ops) | 3985 | if (!dai->driver->ops) |
| 4001 | dai->driver->ops = &null_dai_ops; | 3986 | dai->driver->ops = &null_dai_ops; |
| 4002 | 3987 | ||
| 4003 | mutex_lock(&client_mutex); | ||
| 4004 | |||
| 4005 | list_for_each_entry(codec, &codec_list, list) { | ||
| 4006 | if (codec->dev == dev) { | ||
| 4007 | dev_dbg(dev, | ||
| 4008 | "ASoC: Mapped DAI %s to CODEC %s\n", | ||
| 4009 | dai->name, codec->name); | ||
| 4010 | dai->codec = codec; | ||
| 4011 | break; | ||
| 4012 | } | ||
| 4013 | } | ||
| 4014 | |||
| 4015 | if (!dai->codec) | 3988 | if (!dai->codec) |
| 4016 | dai->dapm.idle_bias_off = 1; | 3989 | dai->dapm.idle_bias_off = 1; |
| 4017 | 3990 | ||
| 4018 | list_add(&dai->list, &dai_list); | 3991 | list_add(&dai->list, &component->dai_list); |
| 4019 | |||
| 4020 | mutex_unlock(&client_mutex); | ||
| 4021 | 3992 | ||
| 4022 | dev_dbg(dai->dev, "ASoC: Registered DAI '%s'\n", dai->name); | 3993 | dev_dbg(dev, "ASoC: Registered DAI '%s'\n", dai->name); |
| 4023 | } | 3994 | } |
| 4024 | 3995 | ||
| 4025 | return 0; | 3996 | return 0; |
| 4026 | 3997 | ||
| 4027 | err: | 3998 | err: |
| 4028 | for (i--; i >= 0; i--) | 3999 | snd_soc_unregister_dais(component); |
| 4029 | snd_soc_unregister_dai(dev); | ||
| 4030 | 4000 | ||
| 4031 | return ret; | 4001 | return ret; |
| 4032 | } | 4002 | } |
| 4033 | 4003 | ||
| 4034 | /** | 4004 | /** |
| 4035 | * snd_soc_unregister_dais - Unregister multiple DAIs from the ASoC core | ||
| 4036 | * | ||
| 4037 | * @dai: Array of DAIs to unregister | ||
| 4038 | * @count: Number of DAIs | ||
| 4039 | */ | ||
| 4040 | static void snd_soc_unregister_dais(struct device *dev, size_t count) | ||
| 4041 | { | ||
| 4042 | int i; | ||
| 4043 | |||
| 4044 | for (i = 0; i < count; i++) | ||
| 4045 | snd_soc_unregister_dai(dev); | ||
| 4046 | } | ||
| 4047 | |||
| 4048 | /** | ||
| 4049 | * snd_soc_register_component - Register a component with the ASoC core | 4005 | * snd_soc_register_component - Register a component with the ASoC core |
| 4050 | * | 4006 | * |
| 4051 | */ | 4007 | */ |
| @@ -4053,6 +4009,7 @@ static int | |||
| 4053 | __snd_soc_register_component(struct device *dev, | 4009 | __snd_soc_register_component(struct device *dev, |
| 4054 | struct snd_soc_component *cmpnt, | 4010 | struct snd_soc_component *cmpnt, |
| 4055 | const struct snd_soc_component_driver *cmpnt_drv, | 4011 | const struct snd_soc_component_driver *cmpnt_drv, |
| 4012 | struct snd_soc_codec *codec, | ||
| 4056 | struct snd_soc_dai_driver *dai_drv, | 4013 | struct snd_soc_dai_driver *dai_drv, |
| 4057 | int num_dai, bool allow_single_dai) | 4014 | int num_dai, bool allow_single_dai) |
| 4058 | { | 4015 | { |
| @@ -4075,20 +4032,10 @@ __snd_soc_register_component(struct device *dev, | |||
| 4075 | cmpnt->driver = cmpnt_drv; | 4032 | cmpnt->driver = cmpnt_drv; |
| 4076 | cmpnt->dai_drv = dai_drv; | 4033 | cmpnt->dai_drv = dai_drv; |
| 4077 | cmpnt->num_dai = num_dai; | 4034 | cmpnt->num_dai = num_dai; |
| 4035 | INIT_LIST_HEAD(&cmpnt->dai_list); | ||
| 4078 | 4036 | ||
| 4079 | /* | 4037 | ret = snd_soc_register_dais(cmpnt, codec, dai_drv, num_dai, |
| 4080 | * snd_soc_register_dai() uses fmt_single_name(), and | 4038 | allow_single_dai); |
| 4081 | * snd_soc_register_dais() uses fmt_multiple_name() | ||
| 4082 | * for dai->name which is used for name based matching | ||
| 4083 | * | ||
| 4084 | * this function is used from cpu/codec. | ||
| 4085 | * allow_single_dai flag can ignore "codec" driver reworking | ||
| 4086 | * since it had been used snd_soc_register_dais(), | ||
| 4087 | */ | ||
| 4088 | if ((1 == num_dai) && allow_single_dai) | ||
| 4089 | ret = snd_soc_register_dai(dev, dai_drv); | ||
| 4090 | else | ||
| 4091 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | ||
| 4092 | if (ret < 0) { | 4039 | if (ret < 0) { |
| 4093 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); | 4040 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); |
| 4094 | goto error_component_name; | 4041 | goto error_component_name; |
| @@ -4121,7 +4068,9 @@ int snd_soc_register_component(struct device *dev, | |||
| 4121 | return -ENOMEM; | 4068 | return -ENOMEM; |
| 4122 | } | 4069 | } |
| 4123 | 4070 | ||
| 4124 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, | 4071 | cmpnt->ignore_pmdown_time = true; |
| 4072 | |||
| 4073 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, NULL, | ||
| 4125 | dai_drv, num_dai, true); | 4074 | dai_drv, num_dai, true); |
| 4126 | } | 4075 | } |
| 4127 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | 4076 | EXPORT_SYMBOL_GPL(snd_soc_register_component); |
| @@ -4141,7 +4090,7 @@ void snd_soc_unregister_component(struct device *dev) | |||
| 4141 | return; | 4090 | return; |
| 4142 | 4091 | ||
| 4143 | found: | 4092 | found: |
| 4144 | snd_soc_unregister_dais(dev, cmpnt->num_dai); | 4093 | snd_soc_unregister_dais(cmpnt); |
| 4145 | 4094 | ||
| 4146 | mutex_lock(&client_mutex); | 4095 | mutex_lock(&client_mutex); |
| 4147 | list_del(&cmpnt->list); | 4096 | list_del(&cmpnt->list); |
| @@ -4319,7 +4268,7 @@ int snd_soc_register_codec(struct device *dev, | |||
| 4319 | codec->volatile_register = codec_drv->volatile_register; | 4268 | codec->volatile_register = codec_drv->volatile_register; |
| 4320 | codec->readable_register = codec_drv->readable_register; | 4269 | codec->readable_register = codec_drv->readable_register; |
| 4321 | codec->writable_register = codec_drv->writable_register; | 4270 | codec->writable_register = codec_drv->writable_register; |
| 4322 | codec->ignore_pmdown_time = codec_drv->ignore_pmdown_time; | 4271 | codec->component.ignore_pmdown_time = codec_drv->ignore_pmdown_time; |
| 4323 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; | 4272 | codec->dapm.bias_level = SND_SOC_BIAS_OFF; |
| 4324 | codec->dapm.dev = dev; | 4273 | codec->dapm.dev = dev; |
| 4325 | codec->dapm.codec = codec; | 4274 | codec->dapm.codec = codec; |
| @@ -4342,7 +4291,7 @@ int snd_soc_register_codec(struct device *dev, | |||
| 4342 | /* register component */ | 4291 | /* register component */ |
| 4343 | ret = __snd_soc_register_component(dev, &codec->component, | 4292 | ret = __snd_soc_register_component(dev, &codec->component, |
| 4344 | &codec_drv->component_driver, | 4293 | &codec_drv->component_driver, |
| 4345 | dai_drv, num_dai, false); | 4294 | codec, dai_drv, num_dai, false); |
| 4346 | if (ret < 0) { | 4295 | if (ret < 0) { |
| 4347 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); | 4296 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); |
| 4348 | goto fail_codec_name; | 4297 | goto fail_codec_name; |
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index 28522bd03b8e..330eaf007d89 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c | |||
| @@ -35,6 +35,86 @@ | |||
| 35 | #define DPCM_MAX_BE_USERS 8 | 35 | #define DPCM_MAX_BE_USERS 8 |
| 36 | 36 | ||
| 37 | /** | 37 | /** |
| 38 | * snd_soc_runtime_activate() - Increment active count for PCM runtime components | ||
| 39 | * @rtd: ASoC PCM runtime that is activated | ||
| 40 | * @stream: Direction of the PCM stream | ||
| 41 | * | ||
| 42 | * Increments the active count for all the DAIs and components attached to a PCM | ||
| 43 | * runtime. Should typically be called when a stream is opened. | ||
| 44 | * | ||
| 45 | * Must be called with the rtd->pcm_mutex being held | ||
| 46 | */ | ||
| 47 | void snd_soc_runtime_activate(struct snd_soc_pcm_runtime *rtd, int stream) | ||
| 48 | { | ||
| 49 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
| 50 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 51 | |||
| 52 | lockdep_assert_held(&rtd->pcm_mutex); | ||
| 53 | |||
| 54 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 55 | cpu_dai->playback_active++; | ||
| 56 | codec_dai->playback_active++; | ||
| 57 | } else { | ||
| 58 | cpu_dai->capture_active++; | ||
| 59 | codec_dai->capture_active++; | ||
| 60 | } | ||
| 61 | |||
| 62 | cpu_dai->active++; | ||
| 63 | codec_dai->active++; | ||
| 64 | cpu_dai->component->active++; | ||
| 65 | codec_dai->component->active++; | ||
| 66 | } | ||
| 67 | |||
| 68 | /** | ||
| 69 | * snd_soc_runtime_deactivate() - Decrement active count for PCM runtime components | ||
| 70 | * @rtd: ASoC PCM runtime that is deactivated | ||
| 71 | * @stream: Direction of the PCM stream | ||
| 72 | * | ||
| 73 | * Decrements the active count for all the DAIs and components attached to a PCM | ||
| 74 | * runtime. Should typically be called when a stream is closed. | ||
| 75 | * | ||
| 76 | * Must be called with the rtd->pcm_mutex being held | ||
| 77 | */ | ||
| 78 | void snd_soc_runtime_deactivate(struct snd_soc_pcm_runtime *rtd, int stream) | ||
| 79 | { | ||
| 80 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | ||
| 81 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | ||
| 82 | |||
| 83 | lockdep_assert_held(&rtd->pcm_mutex); | ||
| 84 | |||
| 85 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 86 | cpu_dai->playback_active--; | ||
| 87 | codec_dai->playback_active--; | ||
| 88 | } else { | ||
| 89 | cpu_dai->capture_active--; | ||
| 90 | codec_dai->capture_active--; | ||
| 91 | } | ||
| 92 | |||
| 93 | cpu_dai->active--; | ||
| 94 | codec_dai->active--; | ||
| 95 | cpu_dai->component->active--; | ||
| 96 | codec_dai->component->active--; | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | ||
| 100 | * snd_soc_runtime_ignore_pmdown_time() - Check whether to ignore the power down delay | ||
| 101 | * @rtd: The ASoC PCM runtime that should be checked. | ||
| 102 | * | ||
| 103 | * This function checks whether the power down delay should be ignored for a | ||
| 104 | * specific PCM runtime. Returns true if the delay is 0, if it the DAI link has | ||
| 105 | * been configured to ignore the delay, or if none of the components benefits | ||
| 106 | * from having the delay. | ||
| 107 | */ | ||
| 108 | bool snd_soc_runtime_ignore_pmdown_time(struct snd_soc_pcm_runtime *rtd) | ||
| 109 | { | ||
| 110 | if (!rtd->pmdown_time || rtd->dai_link->ignore_pmdown_time) | ||
| 111 | return true; | ||
| 112 | |||
| 113 | return rtd->cpu_dai->component->ignore_pmdown_time && | ||
| 114 | rtd->codec_dai->component->ignore_pmdown_time; | ||
| 115 | } | ||
| 116 | |||
| 117 | /** | ||
| 38 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters | 118 | * snd_soc_set_runtime_hwparams - set the runtime hardware parameters |
| 39 | * @substream: the pcm substream | 119 | * @substream: the pcm substream |
| 40 | * @hw: the hardware parameters | 120 | * @hw: the hardware parameters |
| @@ -378,16 +458,9 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) | |||
| 378 | runtime->hw.rate_max); | 458 | runtime->hw.rate_max); |
| 379 | 459 | ||
| 380 | dynamic: | 460 | dynamic: |
| 381 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 461 | |
| 382 | cpu_dai->playback_active++; | 462 | snd_soc_runtime_activate(rtd, substream->stream); |
| 383 | codec_dai->playback_active++; | 463 | |
| 384 | } else { | ||
| 385 | cpu_dai->capture_active++; | ||
| 386 | codec_dai->capture_active++; | ||
| 387 | } | ||
| 388 | cpu_dai->active++; | ||
| 389 | codec_dai->active++; | ||
| 390 | rtd->codec->active++; | ||
| 391 | mutex_unlock(&rtd->pcm_mutex); | 464 | mutex_unlock(&rtd->pcm_mutex); |
| 392 | return 0; | 465 | return 0; |
| 393 | 466 | ||
| @@ -459,21 +532,10 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
| 459 | struct snd_soc_platform *platform = rtd->platform; | 532 | struct snd_soc_platform *platform = rtd->platform; |
| 460 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; | 533 | struct snd_soc_dai *cpu_dai = rtd->cpu_dai; |
| 461 | struct snd_soc_dai *codec_dai = rtd->codec_dai; | 534 | struct snd_soc_dai *codec_dai = rtd->codec_dai; |
| 462 | struct snd_soc_codec *codec = rtd->codec; | ||
| 463 | 535 | ||
| 464 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); | 536 | mutex_lock_nested(&rtd->pcm_mutex, rtd->pcm_subclass); |
| 465 | 537 | ||
| 466 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 538 | snd_soc_runtime_deactivate(rtd, substream->stream); |
| 467 | cpu_dai->playback_active--; | ||
| 468 | codec_dai->playback_active--; | ||
| 469 | } else { | ||
| 470 | cpu_dai->capture_active--; | ||
| 471 | codec_dai->capture_active--; | ||
| 472 | } | ||
| 473 | |||
| 474 | cpu_dai->active--; | ||
| 475 | codec_dai->active--; | ||
| 476 | codec->active--; | ||
| 477 | 539 | ||
| 478 | /* clear the corresponding DAIs rate when inactive */ | 540 | /* clear the corresponding DAIs rate when inactive */ |
| 479 | if (!cpu_dai->active) | 541 | if (!cpu_dai->active) |
| @@ -496,8 +558,7 @@ static int soc_pcm_close(struct snd_pcm_substream *substream) | |||
| 496 | cpu_dai->runtime = NULL; | 558 | cpu_dai->runtime = NULL; |
| 497 | 559 | ||
| 498 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 560 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 499 | if (!rtd->pmdown_time || codec->ignore_pmdown_time || | 561 | if (snd_soc_runtime_ignore_pmdown_time(rtd)) { |
| 500 | rtd->dai_link->ignore_pmdown_time) { | ||
| 501 | /* powered down playback stream now */ | 562 | /* powered down playback stream now */ |
| 502 | snd_soc_dapm_stream_event(rtd, | 563 | snd_soc_dapm_stream_event(rtd, |
| 503 | SNDRV_PCM_STREAM_PLAYBACK, | 564 | SNDRV_PCM_STREAM_PLAYBACK, |
