diff options
| -rw-r--r-- | include/sound/soc.h | 41 | ||||
| -rw-r--r-- | sound/soc/soc-core.c | 237 |
2 files changed, 174 insertions, 104 deletions
diff --git a/include/sound/soc.h b/include/sound/soc.h index a72af6327987..b13eecbaea78 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h | |||
| @@ -13,6 +13,7 @@ | |||
| 13 | #ifndef __LINUX_SND_SOC_H | 13 | #ifndef __LINUX_SND_SOC_H |
| 14 | #define __LINUX_SND_SOC_H | 14 | #define __LINUX_SND_SOC_H |
| 15 | 15 | ||
| 16 | #include <linux/of.h> | ||
| 16 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
| 17 | #include <linux/types.h> | 18 | #include <linux/types.h> |
| 18 | #include <linux/notifier.h> | 19 | #include <linux/notifier.h> |
| @@ -630,6 +631,26 @@ struct snd_soc_compr_ops { | |||
| 630 | int (*trigger)(struct snd_compr_stream *); | 631 | int (*trigger)(struct snd_compr_stream *); |
| 631 | }; | 632 | }; |
| 632 | 633 | ||
| 634 | /* component interface */ | ||
| 635 | struct snd_soc_component_driver { | ||
| 636 | const char *name; | ||
| 637 | |||
| 638 | /* DT */ | ||
| 639 | int (*of_xlate_dai_name)(struct snd_soc_component *component, | ||
| 640 | struct of_phandle_args *args, | ||
| 641 | const char **dai_name); | ||
| 642 | }; | ||
| 643 | |||
| 644 | struct snd_soc_component { | ||
| 645 | const char *name; | ||
| 646 | int id; | ||
| 647 | int num_dai; | ||
| 648 | struct device *dev; | ||
| 649 | struct list_head list; | ||
| 650 | |||
| 651 | const struct snd_soc_component_driver *driver; | ||
| 652 | }; | ||
| 653 | |||
| 633 | /* SoC Audio Codec device */ | 654 | /* SoC Audio Codec device */ |
| 634 | struct snd_soc_codec { | 655 | struct snd_soc_codec { |
| 635 | const char *name; | 656 | const char *name; |
| @@ -670,6 +691,9 @@ struct snd_soc_codec { | |||
| 670 | struct mutex cache_rw_mutex; | 691 | struct mutex cache_rw_mutex; |
| 671 | int val_bytes; | 692 | int val_bytes; |
| 672 | 693 | ||
| 694 | /* component */ | ||
| 695 | struct snd_soc_component component; | ||
| 696 | |||
| 673 | /* dapm */ | 697 | /* dapm */ |
| 674 | struct snd_soc_dapm_context dapm; | 698 | struct snd_soc_dapm_context dapm; |
| 675 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ | 699 | unsigned int ignore_pmdown_time:1; /* pmdown_time is ignored at stop */ |
| @@ -688,6 +712,7 @@ struct snd_soc_codec_driver { | |||
| 688 | int (*remove)(struct snd_soc_codec *); | 712 | int (*remove)(struct snd_soc_codec *); |
| 689 | int (*suspend)(struct snd_soc_codec *); | 713 | int (*suspend)(struct snd_soc_codec *); |
| 690 | int (*resume)(struct snd_soc_codec *); | 714 | int (*resume)(struct snd_soc_codec *); |
| 715 | struct snd_soc_component_driver component_driver; | ||
| 691 | 716 | ||
| 692 | /* Default control and setup, added after probe() is run */ | 717 | /* Default control and setup, added after probe() is run */ |
| 693 | const struct snd_kcontrol_new *controls; | 718 | const struct snd_kcontrol_new *controls; |
| @@ -801,20 +826,6 @@ struct snd_soc_platform { | |||
| 801 | #endif | 826 | #endif |
| 802 | }; | 827 | }; |
| 803 | 828 | ||
| 804 | struct snd_soc_component_driver { | ||
| 805 | const char *name; | ||
| 806 | }; | ||
| 807 | |||
| 808 | struct snd_soc_component { | ||
| 809 | const char *name; | ||
| 810 | int id; | ||
| 811 | int num_dai; | ||
| 812 | struct device *dev; | ||
| 813 | struct list_head list; | ||
| 814 | |||
| 815 | const struct snd_soc_component_driver *driver; | ||
| 816 | }; | ||
| 817 | |||
| 818 | struct snd_soc_dai_link { | 829 | struct snd_soc_dai_link { |
| 819 | /* config - must be set by machine driver */ | 830 | /* config - must be set by machine driver */ |
| 820 | const char *name; /* Codec name */ | 831 | const char *name; /* Codec name */ |
| @@ -1145,6 +1156,8 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card, | |||
| 1145 | const char *propname); | 1156 | const char *propname); |
| 1146 | unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | 1157 | unsigned int snd_soc_of_parse_daifmt(struct device_node *np, |
| 1147 | const char *prefix); | 1158 | const char *prefix); |
| 1159 | int snd_soc_of_get_dai_name(struct device_node *of_node, | ||
| 1160 | const char **dai_name); | ||
| 1148 | 1161 | ||
| 1149 | #include <sound/soc-dai.h> | 1162 | #include <sound/soc-dai.h> |
| 1150 | 1163 | ||
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 16a3930c6375..67cfb5f5ca96 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c | |||
| @@ -3996,6 +3996,112 @@ static void snd_soc_unregister_dais(struct device *dev, size_t count) | |||
| 3996 | } | 3996 | } |
| 3997 | 3997 | ||
| 3998 | /** | 3998 | /** |
| 3999 | * snd_soc_register_component - Register a component with the ASoC core | ||
| 4000 | * | ||
| 4001 | */ | ||
| 4002 | static int | ||
| 4003 | __snd_soc_register_component(struct device *dev, | ||
| 4004 | struct snd_soc_component *cmpnt, | ||
| 4005 | const struct snd_soc_component_driver *cmpnt_drv, | ||
| 4006 | struct snd_soc_dai_driver *dai_drv, | ||
| 4007 | int num_dai, bool allow_single_dai) | ||
| 4008 | { | ||
| 4009 | int ret; | ||
| 4010 | |||
| 4011 | dev_dbg(dev, "component register %s\n", dev_name(dev)); | ||
| 4012 | |||
| 4013 | if (!cmpnt) { | ||
| 4014 | dev_err(dev, "ASoC: Failed to connecting component\n"); | ||
| 4015 | return -ENOMEM; | ||
| 4016 | } | ||
| 4017 | |||
| 4018 | cmpnt->name = fmt_single_name(dev, &cmpnt->id); | ||
| 4019 | if (!cmpnt->name) { | ||
| 4020 | dev_err(dev, "ASoC: Failed to simplifying name\n"); | ||
| 4021 | return -ENOMEM; | ||
| 4022 | } | ||
| 4023 | |||
| 4024 | cmpnt->dev = dev; | ||
| 4025 | cmpnt->driver = cmpnt_drv; | ||
| 4026 | cmpnt->num_dai = num_dai; | ||
| 4027 | |||
| 4028 | /* | ||
| 4029 | * snd_soc_register_dai() uses fmt_single_name(), and | ||
| 4030 | * snd_soc_register_dais() uses fmt_multiple_name() | ||
| 4031 | * for dai->name which is used for name based matching | ||
| 4032 | * | ||
| 4033 | * this function is used from cpu/codec. | ||
| 4034 | * allow_single_dai flag can ignore "codec" driver reworking | ||
| 4035 | * since it had been used snd_soc_register_dais(), | ||
| 4036 | */ | ||
| 4037 | if ((1 == num_dai) && allow_single_dai) | ||
| 4038 | ret = snd_soc_register_dai(dev, dai_drv); | ||
| 4039 | else | ||
| 4040 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | ||
| 4041 | if (ret < 0) { | ||
| 4042 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); | ||
| 4043 | goto error_component_name; | ||
| 4044 | } | ||
| 4045 | |||
| 4046 | mutex_lock(&client_mutex); | ||
| 4047 | list_add(&cmpnt->list, &component_list); | ||
| 4048 | mutex_unlock(&client_mutex); | ||
| 4049 | |||
| 4050 | dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); | ||
| 4051 | |||
| 4052 | return ret; | ||
| 4053 | |||
| 4054 | error_component_name: | ||
| 4055 | kfree(cmpnt->name); | ||
| 4056 | |||
| 4057 | return ret; | ||
| 4058 | } | ||
| 4059 | |||
| 4060 | int snd_soc_register_component(struct device *dev, | ||
| 4061 | const struct snd_soc_component_driver *cmpnt_drv, | ||
| 4062 | struct snd_soc_dai_driver *dai_drv, | ||
| 4063 | int num_dai) | ||
| 4064 | { | ||
| 4065 | struct snd_soc_component *cmpnt; | ||
| 4066 | |||
| 4067 | cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); | ||
| 4068 | if (!cmpnt) { | ||
| 4069 | dev_err(dev, "ASoC: Failed to allocate memory\n"); | ||
| 4070 | return -ENOMEM; | ||
| 4071 | } | ||
| 4072 | |||
| 4073 | return __snd_soc_register_component(dev, cmpnt, cmpnt_drv, | ||
| 4074 | dai_drv, num_dai, true); | ||
| 4075 | } | ||
| 4076 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | ||
| 4077 | |||
| 4078 | /** | ||
| 4079 | * snd_soc_unregister_component - Unregister a component from the ASoC core | ||
| 4080 | * | ||
| 4081 | */ | ||
| 4082 | void snd_soc_unregister_component(struct device *dev) | ||
| 4083 | { | ||
| 4084 | struct snd_soc_component *cmpnt; | ||
| 4085 | |||
| 4086 | list_for_each_entry(cmpnt, &component_list, list) { | ||
| 4087 | if (dev == cmpnt->dev) | ||
| 4088 | goto found; | ||
| 4089 | } | ||
| 4090 | return; | ||
| 4091 | |||
| 4092 | found: | ||
| 4093 | snd_soc_unregister_dais(dev, cmpnt->num_dai); | ||
| 4094 | |||
| 4095 | mutex_lock(&client_mutex); | ||
| 4096 | list_del(&cmpnt->list); | ||
| 4097 | mutex_unlock(&client_mutex); | ||
| 4098 | |||
| 4099 | dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); | ||
| 4100 | kfree(cmpnt->name); | ||
| 4101 | } | ||
| 4102 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); | ||
| 4103 | |||
| 4104 | /** | ||
| 3999 | * snd_soc_add_platform - Add a platform to the ASoC core | 4105 | * snd_soc_add_platform - Add a platform to the ASoC core |
| 4000 | * @dev: The parent device for the platform | 4106 | * @dev: The parent device for the platform |
| 4001 | * @platform: The platform to add | 4107 | * @platform: The platform to add |
| @@ -4182,10 +4288,12 @@ int snd_soc_register_codec(struct device *dev, | |||
| 4182 | list_add(&codec->list, &codec_list); | 4288 | list_add(&codec->list, &codec_list); |
| 4183 | mutex_unlock(&client_mutex); | 4289 | mutex_unlock(&client_mutex); |
| 4184 | 4290 | ||
| 4185 | /* register any DAIs */ | 4291 | /* register component */ |
| 4186 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | 4292 | ret = __snd_soc_register_component(dev, &codec->component, |
| 4293 | &codec_drv->component_driver, | ||
| 4294 | dai_drv, num_dai, false); | ||
| 4187 | if (ret < 0) { | 4295 | if (ret < 0) { |
| 4188 | dev_err(codec->dev, "ASoC: Failed to regster DAIs: %d\n", ret); | 4296 | dev_err(codec->dev, "ASoC: Failed to regster component: %d\n", ret); |
| 4189 | goto fail_codec_name; | 4297 | goto fail_codec_name; |
| 4190 | } | 4298 | } |
| 4191 | 4299 | ||
| @@ -4220,7 +4328,7 @@ void snd_soc_unregister_codec(struct device *dev) | |||
| 4220 | return; | 4328 | return; |
| 4221 | 4329 | ||
| 4222 | found: | 4330 | found: |
| 4223 | snd_soc_unregister_dais(dev, codec->num_dai); | 4331 | snd_soc_unregister_component(dev); |
| 4224 | 4332 | ||
| 4225 | mutex_lock(&client_mutex); | 4333 | mutex_lock(&client_mutex); |
| 4226 | list_del(&codec->list); | 4334 | list_del(&codec->list); |
| @@ -4234,92 +4342,6 @@ found: | |||
| 4234 | } | 4342 | } |
| 4235 | EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); | 4343 | EXPORT_SYMBOL_GPL(snd_soc_unregister_codec); |
| 4236 | 4344 | ||
| 4237 | |||
| 4238 | /** | ||
| 4239 | * snd_soc_register_component - Register a component with the ASoC core | ||
| 4240 | * | ||
| 4241 | */ | ||
| 4242 | int snd_soc_register_component(struct device *dev, | ||
| 4243 | const struct snd_soc_component_driver *cmpnt_drv, | ||
| 4244 | struct snd_soc_dai_driver *dai_drv, | ||
| 4245 | int num_dai) | ||
| 4246 | { | ||
| 4247 | struct snd_soc_component *cmpnt; | ||
| 4248 | int ret; | ||
| 4249 | |||
| 4250 | dev_dbg(dev, "component register %s\n", dev_name(dev)); | ||
| 4251 | |||
| 4252 | cmpnt = devm_kzalloc(dev, sizeof(*cmpnt), GFP_KERNEL); | ||
| 4253 | if (!cmpnt) { | ||
| 4254 | dev_err(dev, "ASoC: Failed to allocate memory\n"); | ||
| 4255 | return -ENOMEM; | ||
| 4256 | } | ||
| 4257 | |||
| 4258 | cmpnt->name = fmt_single_name(dev, &cmpnt->id); | ||
| 4259 | if (!cmpnt->name) { | ||
| 4260 | dev_err(dev, "ASoC: Failed to simplifying name\n"); | ||
| 4261 | return -ENOMEM; | ||
| 4262 | } | ||
| 4263 | |||
| 4264 | cmpnt->dev = dev; | ||
| 4265 | cmpnt->driver = cmpnt_drv; | ||
| 4266 | cmpnt->num_dai = num_dai; | ||
| 4267 | |||
| 4268 | /* | ||
| 4269 | * snd_soc_register_dai() uses fmt_single_name(), and | ||
| 4270 | * snd_soc_register_dais() uses fmt_multiple_name() | ||
| 4271 | * for dai->name which is used for name based matching | ||
| 4272 | */ | ||
| 4273 | if (1 == num_dai) | ||
| 4274 | ret = snd_soc_register_dai(dev, dai_drv); | ||
| 4275 | else | ||
| 4276 | ret = snd_soc_register_dais(dev, dai_drv, num_dai); | ||
| 4277 | if (ret < 0) { | ||
| 4278 | dev_err(dev, "ASoC: Failed to regster DAIs: %d\n", ret); | ||
| 4279 | goto error_component_name; | ||
| 4280 | } | ||
| 4281 | |||
| 4282 | mutex_lock(&client_mutex); | ||
| 4283 | list_add(&cmpnt->list, &component_list); | ||
| 4284 | mutex_unlock(&client_mutex); | ||
| 4285 | |||
| 4286 | dev_dbg(cmpnt->dev, "ASoC: Registered component '%s'\n", cmpnt->name); | ||
| 4287 | |||
| 4288 | return ret; | ||
| 4289 | |||
| 4290 | error_component_name: | ||
| 4291 | kfree(cmpnt->name); | ||
| 4292 | |||
| 4293 | return ret; | ||
| 4294 | } | ||
| 4295 | EXPORT_SYMBOL_GPL(snd_soc_register_component); | ||
| 4296 | |||
| 4297 | /** | ||
| 4298 | * snd_soc_unregister_component - Unregister a component from the ASoC core | ||
| 4299 | * | ||
| 4300 | */ | ||
| 4301 | void snd_soc_unregister_component(struct device *dev) | ||
| 4302 | { | ||
| 4303 | struct snd_soc_component *cmpnt; | ||
| 4304 | |||
| 4305 | list_for_each_entry(cmpnt, &component_list, list) { | ||
| 4306 | if (dev == cmpnt->dev) | ||
| 4307 | goto found; | ||
| 4308 | } | ||
| 4309 | return; | ||
| 4310 | |||
| 4311 | found: | ||
| 4312 | snd_soc_unregister_dais(dev, cmpnt->num_dai); | ||
| 4313 | |||
| 4314 | mutex_lock(&client_mutex); | ||
| 4315 | list_del(&cmpnt->list); | ||
| 4316 | mutex_unlock(&client_mutex); | ||
| 4317 | |||
| 4318 | dev_dbg(dev, "ASoC: Unregistered component '%s'\n", cmpnt->name); | ||
| 4319 | kfree(cmpnt->name); | ||
| 4320 | } | ||
| 4321 | EXPORT_SYMBOL_GPL(snd_soc_unregister_component); | ||
| 4322 | |||
| 4323 | /* Retrieve a card's name from device tree */ | 4345 | /* Retrieve a card's name from device tree */ |
| 4324 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, | 4346 | int snd_soc_of_parse_card_name(struct snd_soc_card *card, |
| 4325 | const char *propname) | 4347 | const char *propname) |
| @@ -4507,6 +4529,41 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np, | |||
| 4507 | } | 4529 | } |
| 4508 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); | 4530 | EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt); |
| 4509 | 4531 | ||
| 4532 | int snd_soc_of_get_dai_name(struct device_node *of_node, | ||
| 4533 | const char **dai_name) | ||
| 4534 | { | ||
| 4535 | struct snd_soc_component *pos; | ||
| 4536 | struct of_phandle_args args; | ||
| 4537 | int ret; | ||
| 4538 | |||
| 4539 | ret = of_parse_phandle_with_args(of_node, "sound-dai", | ||
| 4540 | "#sound-dai-cells", 0, &args); | ||
| 4541 | if (ret) | ||
| 4542 | return ret; | ||
| 4543 | |||
| 4544 | ret = -EPROBE_DEFER; | ||
| 4545 | |||
| 4546 | mutex_lock(&client_mutex); | ||
| 4547 | list_for_each_entry(pos, &component_list, list) { | ||
| 4548 | if (pos->dev->of_node != args.np) | ||
| 4549 | continue; | ||
| 4550 | |||
| 4551 | if (!pos->driver->of_xlate_dai_name) { | ||
| 4552 | ret = -ENOSYS; | ||
| 4553 | break; | ||
| 4554 | } | ||
| 4555 | |||
| 4556 | ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name); | ||
| 4557 | break; | ||
| 4558 | } | ||
| 4559 | mutex_unlock(&client_mutex); | ||
| 4560 | |||
| 4561 | of_node_put(args.np); | ||
| 4562 | |||
| 4563 | return ret; | ||
| 4564 | } | ||
| 4565 | EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name); | ||
| 4566 | |||
| 4510 | static int __init snd_soc_init(void) | 4567 | static int __init snd_soc_init(void) |
| 4511 | { | 4568 | { |
| 4512 | #ifdef CONFIG_DEBUG_FS | 4569 | #ifdef CONFIG_DEBUG_FS |
