From 70f3af3ca15affaef3d026a5aa6e44c4627ea6c7 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:45 +0100 Subject: ASoC: Properly handle AC'97 device lifetime management The memory that a struct device is contained in must not be freed except from within the device's release callback. The ASoC code currently does not adhere to this rule for the AC'97 device. This patch fixes it by moving the freeing of the AC'97 to the release callback and splitting up the registration and unregistration of the device into separate steps for getting/putting the reference to the device and adding/removing it to the device hierarchy. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4c8f8a23a0e9..7084c6f1285a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -504,13 +504,10 @@ EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) { if (codec->ac97->dev.bus) - device_unregister(&codec->ac97->dev); + device_del(&codec->ac97->dev); return 0; } -/* stop no dev release warning */ -static void soc_ac97_device_release(struct device *dev){} - /* register ac97 codec to bus */ static int soc_ac97_dev_register(struct snd_soc_codec *codec) { @@ -518,12 +515,11 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) codec->ac97->dev.bus = &ac97_bus_type; codec->ac97->dev.parent = codec->component.card->dev; - codec->ac97->dev.release = soc_ac97_device_release; dev_set_name(&codec->ac97->dev, "%d-%d:%s", codec->component.card->snd_card->number, 0, codec->component.name); - err = device_register(&codec->ac97->dev); + err = device_add(&codec->ac97->dev); if (err < 0) { dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); codec->ac97->dev.bus = NULL; @@ -1948,6 +1944,11 @@ static struct platform_driver soc_driver = { .remove = soc_remove, }; +static void soc_ac97_device_release(struct device *dev) +{ + kfree(to_ac97_t(dev)); +} + /** * snd_soc_new_ac97_codec - initailise AC97 device * @codec: audio codec @@ -1972,12 +1973,14 @@ int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, codec->ac97->bus->ops = ops; codec->ac97->num = num; + codec->ac97->dev.release = soc_ac97_device_release; /* * Mark the AC97 device to be created by us. This way we ensure that the * device will be registered with the device subsystem later on. */ codec->ac97_created = 1; + device_initialize(&codec->ac97->dev); return 0; } @@ -2152,7 +2155,8 @@ void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) soc_unregister_ac97_codec(codec); #endif kfree(codec->ac97->bus); - kfree(codec->ac97); + codec->ac97->bus = NULL; + put_device(&codec->ac97->dev); codec->ac97 = NULL; codec->ac97_created = 0; } -- cgit From 336b8423e285174ebecf02a743d69913b83bbc48 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:46 +0100 Subject: ASoC: Move AC'97 support to its own file Currently the AC'97 support is splattered all throughout soc-core.c. Some parts are #ifdef'd some parts are not. This patch moves the AC'97 support to its own file, this should make the code a bit more clearer and also makes it possible to easily not compile it into the kernel when not needed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 352 +-------------------------------------------------- 1 file changed, 4 insertions(+), 348 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 7084c6f1285a..026722f5ebf4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -34,9 +34,6 @@ #include #include #include -#include -#include -#include #include #include #include @@ -69,16 +66,6 @@ static int pmdown_time = 5000; module_param(pmdown_time, int, 0); MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)"); -struct snd_ac97_reset_cfg { - struct pinctrl *pctl; - struct pinctrl_state *pstate_reset; - struct pinctrl_state *pstate_warm_reset; - struct pinctrl_state *pstate_run; - int gpio_sdata; - int gpio_sync; - int gpio_reset; -}; - /* returns the minimum number of bytes needed to represent * a particular given value */ static int min_bytes_needed(unsigned long val) @@ -499,36 +486,6 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime); -#ifdef CONFIG_SND_SOC_AC97_BUS -/* unregister ac97 codec */ -static int soc_ac97_dev_unregister(struct snd_soc_codec *codec) -{ - if (codec->ac97->dev.bus) - device_del(&codec->ac97->dev); - return 0; -} - -/* register ac97 codec to bus */ -static int soc_ac97_dev_register(struct snd_soc_codec *codec) -{ - int err; - - codec->ac97->dev.bus = &ac97_bus_type; - codec->ac97->dev.parent = codec->component.card->dev; - - dev_set_name(&codec->ac97->dev, "%d-%d:%s", - codec->component.card->snd_card->number, 0, - codec->component.name); - err = device_add(&codec->ac97->dev); - if (err < 0) { - dev_err(codec->dev, "ASoC: Can't register ac97 bus\n"); - codec->ac97->dev.bus = NULL; - return err; - } - return 0; -} -#endif - static void codec2codec_close_delayed_work(struct work_struct *work) { /* Currently nothing to do for c2c links @@ -1418,84 +1375,11 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) } } - /* add platform data for AC97 devices */ - for (i = 0; i < rtd->num_codecs; i++) { - if (rtd->codec_dais[i]->driver->ac97_control) - snd_ac97_dev_add_pdata(rtd->codec_dais[i]->codec->ac97, - rtd->cpu_dai->ac97_pdata); - } - - return 0; -} - -#ifdef CONFIG_SND_SOC_AC97_BUS -static int soc_register_ac97_codec(struct snd_soc_codec *codec, - struct snd_soc_dai *codec_dai) -{ - int ret; - - /* Only instantiate AC97 if not already done by the adaptor - * for the generic AC97 subsystem. - */ - if (codec_dai->driver->ac97_control && !codec->ac97_registered) { - /* - * It is possible that the AC97 device is already registered to - * the device subsystem. This happens when the device is created - * via snd_ac97_mixer(). Currently only SoC codec that does so - * is the generic AC97 glue but others migh emerge. - * - * In those cases we don't try to register the device again. - */ - if (!codec->ac97_created) - return 0; - - ret = soc_ac97_dev_register(codec); - if (ret < 0) { - dev_err(codec->dev, - "ASoC: AC97 device register failed: %d\n", ret); - return ret; - } - - codec->ac97_registered = 1; - } - return 0; -} - -static void soc_unregister_ac97_codec(struct snd_soc_codec *codec) -{ - if (codec->ac97_registered) { - soc_ac97_dev_unregister(codec); - codec->ac97_registered = 0; - } -} - -static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) -{ - int i, ret; - - for (i = 0; i < rtd->num_codecs; i++) { - struct snd_soc_dai *codec_dai = rtd->codec_dais[i]; - - ret = soc_register_ac97_codec(codec_dai->codec, codec_dai); - if (ret) { - while (--i >= 0) - soc_unregister_ac97_codec(codec_dai->codec); - return ret; - } - } + snd_soc_ac97_add_pdata(rtd); return 0; } -static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd) -{ - int i; - - for (i = 0; i < rtd->num_codecs; i++) - soc_unregister_ac97_codec(rtd->codec_dais[i]->codec); -} -#endif - static int soc_bind_aux_dev(struct snd_soc_card *card, int num) { struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num]; @@ -1789,19 +1673,9 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto probe_aux_dev_err; } -#ifdef CONFIG_SND_SOC_AC97_BUS - /* register any AC97 codecs */ - for (i = 0; i < card->num_rtd; i++) { - ret = soc_register_ac97_dai_link(&card->rtd[i]); - if (ret < 0) { - dev_err(card->dev, - "ASoC: failed to register AC97: %d\n", ret); - while (--i >= 0) - soc_unregister_ac97_dai_link(&card->rtd[i]); - goto probe_aux_dev_err; - } - } -#endif + ret = snd_soc_ac97_register_dai_links(card); + if (ret < 0) + goto probe_aux_dev_err; card->instantiated = 1; snd_soc_dapm_sync(&card->dapm); @@ -1944,224 +1818,6 @@ static struct platform_driver soc_driver = { .remove = soc_remove, }; -static void soc_ac97_device_release(struct device *dev) -{ - kfree(to_ac97_t(dev)); -} - -/** - * snd_soc_new_ac97_codec - initailise AC97 device - * @codec: audio codec - * @ops: AC97 bus operations - * @num: AC97 codec number - * - * Initialises AC97 codec resources for use by ad-hoc devices only. - */ -int snd_soc_new_ac97_codec(struct snd_soc_codec *codec, - struct snd_ac97_bus_ops *ops, int num) -{ - codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL); - if (codec->ac97 == NULL) - return -ENOMEM; - - codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL); - if (codec->ac97->bus == NULL) { - kfree(codec->ac97); - codec->ac97 = NULL; - return -ENOMEM; - } - - codec->ac97->bus->ops = ops; - codec->ac97->num = num; - codec->ac97->dev.release = soc_ac97_device_release; - - /* - * Mark the AC97 device to be created by us. This way we ensure that the - * device will be registered with the device subsystem later on. - */ - codec->ac97_created = 1; - device_initialize(&codec->ac97->dev); - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec); - -static struct snd_ac97_reset_cfg snd_ac97_rst_cfg; - -static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97) -{ - struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; - - pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset); - - gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1); - - udelay(10); - - gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); - - pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); - msleep(2); -} - -static void snd_soc_ac97_reset(struct snd_ac97 *ac97) -{ - struct pinctrl *pctl = snd_ac97_rst_cfg.pctl; - - pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset); - - gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0); - gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0); - gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0); - - udelay(10); - - gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1); - - pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run); - msleep(2); -} - -static int snd_soc_ac97_parse_pinctl(struct device *dev, - struct snd_ac97_reset_cfg *cfg) -{ - struct pinctrl *p; - struct pinctrl_state *state; - int gpio; - int ret; - - p = devm_pinctrl_get(dev); - if (IS_ERR(p)) { - dev_err(dev, "Failed to get pinctrl\n"); - return PTR_ERR(p); - } - cfg->pctl = p; - - state = pinctrl_lookup_state(p, "ac97-reset"); - if (IS_ERR(state)) { - dev_err(dev, "Can't find pinctrl state ac97-reset\n"); - return PTR_ERR(state); - } - cfg->pstate_reset = state; - - state = pinctrl_lookup_state(p, "ac97-warm-reset"); - if (IS_ERR(state)) { - dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n"); - return PTR_ERR(state); - } - cfg->pstate_warm_reset = state; - - state = pinctrl_lookup_state(p, "ac97-running"); - if (IS_ERR(state)) { - dev_err(dev, "Can't find pinctrl state ac97-running\n"); - return PTR_ERR(state); - } - cfg->pstate_run = state; - - gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0); - if (gpio < 0) { - dev_err(dev, "Can't find ac97-sync gpio\n"); - return gpio; - } - ret = devm_gpio_request(dev, gpio, "AC97 link sync"); - if (ret) { - dev_err(dev, "Failed requesting ac97-sync gpio\n"); - return ret; - } - cfg->gpio_sync = gpio; - - gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1); - if (gpio < 0) { - dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio); - return gpio; - } - ret = devm_gpio_request(dev, gpio, "AC97 link sdata"); - if (ret) { - dev_err(dev, "Failed requesting ac97-sdata gpio\n"); - return ret; - } - cfg->gpio_sdata = gpio; - - gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2); - if (gpio < 0) { - dev_err(dev, "Can't find ac97-reset gpio\n"); - return gpio; - } - ret = devm_gpio_request(dev, gpio, "AC97 link reset"); - if (ret) { - dev_err(dev, "Failed requesting ac97-reset gpio\n"); - return ret; - } - cfg->gpio_reset = gpio; - - return 0; -} - -struct snd_ac97_bus_ops *soc_ac97_ops; -EXPORT_SYMBOL_GPL(soc_ac97_ops); - -int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops) -{ - if (ops == soc_ac97_ops) - return 0; - - if (soc_ac97_ops && ops) - return -EBUSY; - - soc_ac97_ops = ops; - - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops); - -/** - * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions - * - * This function sets the reset and warm_reset properties of ops and parses - * the device node of pdev to get pinctrl states and gpio numbers to use. - */ -int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops, - struct platform_device *pdev) -{ - struct device *dev = &pdev->dev; - struct snd_ac97_reset_cfg cfg; - int ret; - - ret = snd_soc_ac97_parse_pinctl(dev, &cfg); - if (ret) - return ret; - - ret = snd_soc_set_ac97_ops(ops); - if (ret) - return ret; - - ops->warm_reset = snd_soc_ac97_warm_reset; - ops->reset = snd_soc_ac97_reset; - - snd_ac97_rst_cfg = cfg; - return 0; -} -EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset); - -/** - * snd_soc_free_ac97_codec - free AC97 codec device - * @codec: audio codec - * - * Frees AC97 codec device resources. - */ -void snd_soc_free_ac97_codec(struct snd_soc_codec *codec) -{ -#ifdef CONFIG_SND_SOC_AC97_BUS - soc_unregister_ac97_codec(codec); -#endif - kfree(codec->ac97->bus); - codec->ac97->bus = NULL; - put_device(&codec->ac97->dev); - codec->ac97 = NULL; - codec->ac97_created = 0; -} -EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); - /** * snd_soc_cnew - create new control * @_template: control template -- cgit From ca005f324ee38308b319c693f40523d959027acf Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:49 +0100 Subject: ASoC: ac97: Drop support for setting platform data via the CPU DAI This has no users since commit f0fba2ad1b6b ("ASoC: multi-component - ASoC Multi-Component Support") which was almost 5 years ago. Given that this runs after CODEC probe functions have been run it also doesn't seem to be that useful. So drop it altogether to make the code simpler. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 026722f5ebf4..d883b4ad03ac 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1375,8 +1375,6 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order) } } - snd_soc_ac97_add_pdata(rtd); - return 0; } -- cgit From 6794f709b7124ff1e574c4f4c9494418ab56c4b4 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:50 +0100 Subject: ASoC: ac97: Drop delayed device registration We have all the information and dependencies we need to initialize and register the device available in snd_soc_new_ac97_codec(). So there is no need to delay the device registration until after the card itself as been registered. This makes the code significantly simpler and also makes it possible to use the AC'97 device in the CODECs probe function. The later will be required to be able to convert the AC'97 CODEC drivers to regmap. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d883b4ad03ac..fba6e28e18d3 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1671,10 +1671,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card) goto probe_aux_dev_err; } - ret = snd_soc_ac97_register_dai_links(card); - if (ret < 0) - goto probe_aux_dev_err; - card->instantiated = 1; snd_soc_dapm_sync(&card->dapm); mutex_unlock(&card->mutex); -- cgit From bc2632140435cc84f9817f1c362479b23dbdfebc Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 10 Nov 2014 22:41:52 +0100 Subject: ASoC: Rename snd_soc_dai_driver struct ac97_control field to bus_control Setting the ac97_control field on a CPU DAI tells the ASoC core that this DAI in addition to audio data also transports control data to the CODEC. This causes the core to suspend the DAI after the CODEC and resume it before the CODEC so communication to the CODEC is still possible. This is not necessarily something that is specific to AC'97 and can be used by other buses with the same requirement. This patch renames the flag from ac97_control to bus_control to make this explicit. While we are at it also change the type from int to bool. The following semantich patch was used for automatic conversion of the drivers: // @@ identifier drv; @@ struct snd_soc_dai_driver drv = { - .ac97_control + .bus_control = - 1 + true }; // Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index fba6e28e18d3..f5bebca84b71 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -550,7 +550,7 @@ int snd_soc_suspend(struct device *dev) if (card->rtd[i].dai_link->ignore_suspend) continue; - if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control) + if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control) cpu_dai->driver->suspend(cpu_dai); if (platform->driver->suspend && !platform->suspended) { platform->driver->suspend(cpu_dai); @@ -629,7 +629,7 @@ int snd_soc_suspend(struct device *dev) if (card->rtd[i].dai_link->ignore_suspend) continue; - if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control) + if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control) cpu_dai->driver->suspend(cpu_dai); /* deactivate pins to sleep state */ @@ -665,14 +665,14 @@ static void soc_resume_deferred(struct work_struct *work) if (card->resume_pre) card->resume_pre(card); - /* resume AC97 DAIs */ + /* resume control bus DAIs */ for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; if (card->rtd[i].dai_link->ignore_suspend) continue; - if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control) + if (cpu_dai->driver->resume && cpu_dai->driver->bus_control) cpu_dai->driver->resume(cpu_dai); } @@ -733,7 +733,7 @@ static void soc_resume_deferred(struct work_struct *work) if (card->rtd[i].dai_link->ignore_suspend) continue; - if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control) + if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control) cpu_dai->driver->resume(cpu_dai); if (platform->driver->resume && platform->suspended) { platform->driver->resume(cpu_dai); @@ -758,7 +758,8 @@ static void soc_resume_deferred(struct work_struct *work) int snd_soc_resume(struct device *dev) { struct snd_soc_card *card = dev_get_drvdata(dev); - int i, ac97_control = 0; + bool bus_control = false; + int i; /* If the card is not initialized yet there is nothing to do */ if (!card->instantiated) @@ -781,17 +782,18 @@ int snd_soc_resume(struct device *dev) } } - /* AC97 devices might have other drivers hanging off them so - * need to resume immediately. Other drivers don't have that - * problem and may take a substantial amount of time to resume + /* + * DAIs that also act as the control bus master might have other drivers + * hanging off them so need to resume immediately. Other drivers don't + * have that problem and may take a substantial amount of time to resume * due to I/O costs and anti-pop so handle them out of line. */ for (i = 0; i < card->num_rtd; i++) { struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai; - ac97_control |= cpu_dai->driver->ac97_control; + bus_control |= cpu_dai->driver->bus_control; } - if (ac97_control) { - dev_dbg(dev, "ASoC: Resuming AC97 immediately\n"); + if (bus_control) { + dev_dbg(dev, "ASoC: Resuming control bus master immediately\n"); soc_resume_deferred(&card->deferred_resume_work); } else { dev_dbg(dev, "ASoC: Scheduling resume work\n"); -- cgit From 20feb881988cdf5f53304c355ae8ee3bf82e80ec Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 18 Nov 2014 19:45:52 +0100 Subject: ASoC: Add helper functions for deferred regmap setup Some drivers (most notably the AC'97 drivers) do not have access to their regmap struct when the component/codec is registered. For those drivers the automatic regmap setup will not work and needs to be done manually, typically from the component/CODEC drivers probe callback. This patch adds a set of helper function to handle deferred regmap initialization as well as early regmap tear-down. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 58 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 11 deletions(-) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 4c8f8a23a0e9..5fd5f08ce24e 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3996,22 +3996,58 @@ static int snd_soc_component_initialize(struct snd_soc_component *component, return 0; } -static void snd_soc_component_init_regmap(struct snd_soc_component *component) +static void snd_soc_component_setup_regmap(struct snd_soc_component *component) { - if (!component->regmap) - component->regmap = dev_get_regmap(component->dev, NULL); - if (component->regmap) { - int val_bytes = regmap_get_val_bytes(component->regmap); - /* Errors are legitimate for non-integer byte multiples */ - if (val_bytes > 0) - component->val_bytes = val_bytes; - } + int val_bytes = regmap_get_val_bytes(component->regmap); + + /* Errors are legitimate for non-integer byte multiples */ + if (val_bytes > 0) + component->val_bytes = val_bytes; +} + +/** + * snd_soc_component_init_regmap() - Initialize regmap instance for the component + * @component: The component for which to initialize the regmap instance + * @regmap: The regmap instance that should be used by the component + * + * This function allows deferred assignment of the regmap instance that is + * associated with the component. Only use this if the regmap instance is not + * yet ready when the component is registered. The function must also be called + * before the first IO attempt of the component. + */ +void snd_soc_component_init_regmap(struct snd_soc_component *component, + struct regmap *regmap) +{ + component->regmap = regmap; + snd_soc_component_setup_regmap(component); } +EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap); + +/** + * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component + * @component: The component for which to de-initialize the regmap instance + * + * Calls regmap_exit() on the regmap instance associated to the component and + * removes the regmap instance from the component. + * + * This function should only be used if snd_soc_component_init_regmap() was used + * to initialize the regmap instance. + */ +void snd_soc_component_exit_regmap(struct snd_soc_component *component) +{ + regmap_exit(component->regmap); + component->regmap = NULL; +} +EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { - if (!component->write && !component->read) - snd_soc_component_init_regmap(component); + if (!component->write && !component->read) { + if (!component->regmap) + component->regmap = dev_get_regmap(component->dev, NULL); + if (component->regmap) + snd_soc_component_setup_regmap(component); + } list_add(&component->list, &component_list); } -- cgit From e874bf5f7647a9fdf14d72dbb376ec95327e3a81 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Tue, 25 Nov 2014 21:41:03 +0100 Subject: ASoC: Disable regmap helpers if regmap is disabled If regmap is disabled there will be no users of the ASoC regmap helpers. Furthermore regmap_exit() will no be defined causing the following compile error: sound/soc/soc-core.c: In function 'snd_soc_component_exit_regmap': sound/soc/soc-core.c:2645:2: error: implicit declaration of function 'regmap_exit' [-Werror=implicit-function-declaration] So disable the helpers if regmap is disabled. Reported-by: kbuild test robot Fixes: 20feb881988c ASoC: Add helper functions for deferred regmap setup") Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- sound/soc/soc-core.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound/soc/soc-core.c') diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index db74c061f520..1edc519d6286 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -3661,6 +3661,8 @@ static void snd_soc_component_setup_regmap(struct snd_soc_component *component) component->val_bytes = val_bytes; } +#ifdef CONFIG_REGMAP + /** * snd_soc_component_init_regmap() - Initialize regmap instance for the component * @component: The component for which to initialize the regmap instance @@ -3696,6 +3698,8 @@ void snd_soc_component_exit_regmap(struct snd_soc_component *component) } EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap); +#endif + static void snd_soc_component_add_unlocked(struct snd_soc_component *component) { if (!component->write && !component->read) { -- cgit