diff options
Diffstat (limited to 'sound/soc/soc-core.c')
-rw-r--r-- | sound/soc/soc-core.c | 434 |
1 files changed, 65 insertions, 369 deletions
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index d8d5449cc48e..e0d3b6f109c4 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -34,9 +34,6 @@ #include <linux/ctype.h> #include <linux/slab.h> #include <linux/of.h> -#include <linux/gpio.h> -#include <linux/of_gpio.h> -#include <sound/ac97_codec.h> #include <sound/core.h> #include <sound/jack.h> #include <sound/pcm.h> @@ -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) @@ -496,40 +483,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_unregister(&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) -{ - int err; - - 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); - 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 @@ -593,7 +546,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); } @@ -667,7 +620,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 */ @@ -703,14 +656,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); } @@ -770,7 +723,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); } @@ -791,7 +744,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) @@ -814,17 +768,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"); @@ -1387,84 +1342,9 @@ 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; - } - } - - 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]; @@ -1758,20 +1638,6 @@ 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 - card->instantiated = 1; snd_soc_dapm_sync(&card->dapm); mutex_unlock(&card->mutex); @@ -1914,216 +1780,6 @@ static struct platform_driver soc_driver = { }; /** - * 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; - - /* - * 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; - - 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); - kfree(codec->ac97); - codec->ac97 = NULL; - codec->ac97_created = 0; -} -EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec); - -/** * snd_soc_cnew - create new control * @_template: control template * @data: control private data @@ -2947,22 +2603,62 @@ 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; +} + +#ifdef CONFIG_REGMAP + +/** + * 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); + +#endif 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); } |