X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fsoc%2Fsoc-core.c;h=1cd149b9ce69e4060c13c1cae1e75115e24c948b;hb=f94b61c2c9fdcc90773c49df9ccf9ede3ad0d7db;hp=637f0d1ea98ed46811e960aefe13b866c3683355;hpb=dec14f8c0eff54549e5747f8a4d1dc6c0347e2dd;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 637f0d1..1cd149b 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -98,7 +98,7 @@ static int soc_ac97_dev_register(struct snd_soc_codec *codec) int err; codec->ac97->dev.bus = &ac97_bus_type; - codec->ac97->dev.parent = NULL; + codec->ac97->dev.parent = codec->card->dev; codec->ac97->dev.release = soc_ac97_device_release; dev_set_name(&codec->ac97->dev, "%d-%d:%s", @@ -133,8 +133,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) mutex_lock(&pcm_mutex); /* startup the audio subsystem */ - if (cpu_dai->ops.startup) { - ret = cpu_dai->ops.startup(substream, cpu_dai); + if (cpu_dai->ops->startup) { + ret = cpu_dai->ops->startup(substream, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't open interface %s\n", cpu_dai->name); @@ -150,8 +150,8 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) } } - if (codec_dai->ops.startup) { - ret = codec_dai->ops.startup(substream, codec_dai); + if (codec_dai->ops->startup) { + ret = codec_dai->ops->startup(substream, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't open codec %s\n", codec_dai->name); @@ -234,7 +234,7 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) cpu_dai->capture.active = codec_dai->capture.active = 1; cpu_dai->active = codec_dai->active = 1; cpu_dai->runtime = runtime; - socdev->codec->active++; + card->codec->active++; mutex_unlock(&pcm_mutex); return 0; @@ -247,8 +247,8 @@ codec_dai_err: platform->pcm_ops->close(substream); platform_err: - if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream, cpu_dai); + if (cpu_dai->ops->shutdown) + cpu_dai->ops->shutdown(substream, cpu_dai); out: mutex_unlock(&pcm_mutex); return ret; @@ -264,7 +264,7 @@ static void close_delayed_work(struct work_struct *work) struct snd_soc_card *card = container_of(work, struct snd_soc_card, delayed_work.work); struct snd_soc_device *socdev = card->socdev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = card->codec; struct snd_soc_dai *codec_dai; int i; @@ -319,7 +319,7 @@ static int soc_codec_close(struct snd_pcm_substream *substream) struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = card->codec; mutex_lock(&pcm_mutex); @@ -340,11 +340,11 @@ static int soc_codec_close(struct snd_pcm_substream *substream) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) snd_soc_dai_digital_mute(codec_dai, 1); - if (cpu_dai->ops.shutdown) - cpu_dai->ops.shutdown(substream, cpu_dai); + if (cpu_dai->ops->shutdown) + cpu_dai->ops->shutdown(substream, cpu_dai); - if (codec_dai->ops.shutdown) - codec_dai->ops.shutdown(substream, codec_dai); + if (codec_dai->ops->shutdown) + codec_dai->ops->shutdown(substream, codec_dai); if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); @@ -387,7 +387,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = card->codec; int ret = 0; mutex_lock(&pcm_mutex); @@ -408,16 +408,16 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream) } } - if (codec_dai->ops.prepare) { - ret = codec_dai->ops.prepare(substream, codec_dai); + if (codec_dai->ops->prepare) { + ret = codec_dai->ops->prepare(substream, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: codec DAI prepare error\n"); goto out; } } - if (cpu_dai->ops.prepare) { - ret = cpu_dai->ops.prepare(substream, cpu_dai); + if (cpu_dai->ops->prepare) { + ret = cpu_dai->ops->prepare(substream, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: cpu DAI prepare error\n"); goto out; @@ -494,8 +494,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - if (codec_dai->ops.hw_params) { - ret = codec_dai->ops.hw_params(substream, params, codec_dai); + if (codec_dai->ops->hw_params) { + ret = codec_dai->ops->hw_params(substream, params, codec_dai); if (ret < 0) { printk(KERN_ERR "asoc: can't set codec %s hw params\n", codec_dai->name); @@ -503,8 +503,8 @@ static int soc_pcm_hw_params(struct snd_pcm_substream *substream, } } - if (cpu_dai->ops.hw_params) { - ret = cpu_dai->ops.hw_params(substream, params, cpu_dai); + if (cpu_dai->ops->hw_params) { + ret = cpu_dai->ops->hw_params(substream, params, cpu_dai); if (ret < 0) { printk(KERN_ERR "asoc: interface %s hw params failed\n", cpu_dai->name); @@ -526,12 +526,12 @@ out: return ret; platform_err: - if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream, cpu_dai); + if (cpu_dai->ops->hw_free) + cpu_dai->ops->hw_free(substream, cpu_dai); interface_err: - if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream, codec_dai); + if (codec_dai->ops->hw_free) + codec_dai->ops->hw_free(substream, codec_dai); codec_err: if (machine->ops && machine->ops->hw_free) @@ -553,7 +553,7 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *cpu_dai = machine->cpu_dai; struct snd_soc_dai *codec_dai = machine->codec_dai; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = card->codec; mutex_lock(&pcm_mutex); @@ -570,11 +570,11 @@ static int soc_pcm_hw_free(struct snd_pcm_substream *substream) platform->pcm_ops->hw_free(substream); /* now free hw params for the DAI's */ - if (codec_dai->ops.hw_free) - codec_dai->ops.hw_free(substream, codec_dai); + if (codec_dai->ops->hw_free) + codec_dai->ops->hw_free(substream, codec_dai); - if (cpu_dai->ops.hw_free) - cpu_dai->ops.hw_free(substream, cpu_dai); + if (cpu_dai->ops->hw_free) + cpu_dai->ops->hw_free(substream, cpu_dai); mutex_unlock(&pcm_mutex); return 0; @@ -591,8 +591,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_soc_dai *codec_dai = machine->codec_dai; int ret; - if (codec_dai->ops.trigger) { - ret = codec_dai->ops.trigger(substream, cmd, codec_dai); + if (codec_dai->ops->trigger) { + ret = codec_dai->ops->trigger(substream, cmd, codec_dai); if (ret < 0) return ret; } @@ -603,8 +603,8 @@ static int soc_pcm_trigger(struct snd_pcm_substream *substream, int cmd) return ret; } - if (cpu_dai->ops.trigger) { - ret = cpu_dai->ops.trigger(substream, cmd, cpu_dai); + if (cpu_dai->ops->trigger) { + ret = cpu_dai->ops->trigger(substream, cmd, cpu_dai); if (ret < 0) return ret; } @@ -629,7 +629,7 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) struct snd_soc_card *card = socdev->card; struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = card->codec; int i; /* Due to the resume being scheduled into a workqueue we could @@ -645,8 +645,8 @@ static int soc_suspend(struct platform_device *pdev, pm_message_t state) /* mute any active DAC's */ for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *dai = card->dai_link[i].codec_dai; - if (dai->ops.digital_mute && dai->playback.active) - dai->ops.digital_mute(dai, 1); + if (dai->ops->digital_mute && dai->playback.active) + dai->ops->digital_mute(dai, 1); } /* suspend all pcms */ @@ -705,7 +705,7 @@ static void soc_resume_deferred(struct work_struct *work) struct snd_soc_device *socdev = card->socdev; struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = card->codec; struct platform_device *pdev = to_platform_device(socdev->dev); int i; @@ -741,8 +741,8 @@ static void soc_resume_deferred(struct work_struct *work) /* unmute any active DACs */ for (i = 0; i < card->num_links; i++) { struct snd_soc_dai *dai = card->dai_link[i].codec_dai; - if (dai->ops.digital_mute && dai->playback.active) - dai->ops.digital_mute(dai, 0); + if (dai->ops->digital_mute && dai->playback.active) + dai->ops->digital_mute(dai, 0); } for (i = 0; i < card->num_links; i++) { @@ -767,11 +767,21 @@ static int soc_resume(struct platform_device *pdev) { struct snd_soc_device *socdev = platform_get_drvdata(pdev); struct snd_soc_card *card = socdev->card; + struct snd_soc_dai *cpu_dai = card->dai_link[0].cpu_dai; - dev_dbg(socdev->dev, "scheduling resume work\n"); - - if (!schedule_work(&card->deferred_resume_work)) - dev_err(socdev->dev, "resume work item may be lost\n"); + /* 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 + * due to I/O costs and anti-pop so handle them out of line. + */ + if (cpu_dai->ac97_control) { + dev_dbg(socdev->dev, "Resuming AC97 immediately\n"); + soc_resume_deferred(&card->deferred_resume_work); + } else { + dev_dbg(socdev->dev, "Scheduling resume work\n"); + if (!schedule_work(&card->deferred_resume_work)) + dev_err(socdev->dev, "resume work item may be lost\n"); + } return 0; } @@ -944,6 +954,9 @@ static int soc_remove(struct platform_device *pdev) struct snd_soc_platform *platform = card->platform; struct snd_soc_codec_device *codec_dev = socdev->codec_dev; + if (!card->instantiated) + return 0; + run_delayed_work(&card->delayed_work); if (platform->remove) @@ -982,8 +995,8 @@ static struct platform_driver soc_driver = { static int soc_new_pcm(struct snd_soc_device *socdev, struct snd_soc_dai_link *dai_link, int num) { - struct snd_soc_codec *codec = socdev->codec; struct snd_soc_card *card = socdev->card; + struct snd_soc_codec *codec = card->codec; struct snd_soc_platform *platform = card->platform; struct snd_soc_dai *codec_dai = dai_link->codec_dai; struct snd_soc_dai *cpu_dai = dai_link->cpu_dai; @@ -998,7 +1011,7 @@ static int soc_new_pcm(struct snd_soc_device *socdev, rtd->dai = dai_link; rtd->socdev = socdev; - codec_dai->codec = socdev->codec; + codec_dai->codec = card->codec; /* check client and interface hw capabilities */ sprintf(new_name, "%s %s-%d", dai_link->stream_name, codec_dai->name, @@ -1048,9 +1061,8 @@ static int soc_new_pcm(struct snd_soc_device *socdev, } /* codec register dump */ -static ssize_t soc_codec_reg_show(struct snd_soc_device *devdata, char *buf) +static ssize_t soc_codec_reg_show(struct snd_soc_codec *codec, char *buf) { - struct snd_soc_codec *codec = devdata->codec; int i, step = 1, count = 0; if (!codec->reg_cache_size) @@ -1090,7 +1102,7 @@ static ssize_t codec_reg_show(struct device *dev, struct device_attribute *attr, char *buf) { struct snd_soc_device *devdata = dev_get_drvdata(dev); - return soc_codec_reg_show(devdata, buf); + return soc_codec_reg_show(devdata->card->codec, buf); } static DEVICE_ATTR(codec_reg, 0444, codec_reg_show, NULL); @@ -1107,12 +1119,10 @@ static ssize_t codec_reg_read_file(struct file *file, char __user *user_buf, { ssize_t ret; struct snd_soc_codec *codec = file->private_data; - struct device *card_dev = codec->card->dev; - struct snd_soc_device *devdata = card_dev->driver_data; char *buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = soc_codec_reg_show(devdata, buf); + ret = soc_codec_reg_show(codec, buf); if (ret >= 0) ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret); kfree(buf); @@ -1309,8 +1319,8 @@ EXPORT_SYMBOL_GPL(snd_soc_test_bits); */ int snd_soc_new_pcms(struct snd_soc_device *socdev, int idx, const char *xid) { - struct snd_soc_codec *codec = socdev->codec; struct snd_soc_card *card = socdev->card; + struct snd_soc_codec *codec = card->codec; int ret, i; mutex_lock(&codec->mutex); @@ -1355,8 +1365,8 @@ EXPORT_SYMBOL_GPL(snd_soc_new_pcms); */ int snd_soc_init_card(struct snd_soc_device *socdev) { - struct snd_soc_codec *codec = socdev->codec; struct snd_soc_card *card = socdev->card; + struct snd_soc_codec *codec = card->codec; int ret = 0, i, ac97 = 0, err = 0; for (i = 0; i < card->num_links; i++) { @@ -1407,7 +1417,7 @@ int snd_soc_init_card(struct snd_soc_device *socdev) if (err < 0) printk(KERN_WARNING "asoc: failed to add codec sysfs files\n"); - soc_init_codec_debugfs(socdev->codec); + soc_init_codec_debugfs(codec); mutex_unlock(&codec->mutex); out: @@ -1424,18 +1434,19 @@ EXPORT_SYMBOL_GPL(snd_soc_init_card); */ void snd_soc_free_pcms(struct snd_soc_device *socdev) { - struct snd_soc_codec *codec = socdev->codec; + struct snd_soc_codec *codec = socdev->card->codec; #ifdef CONFIG_SND_SOC_AC97_BUS struct snd_soc_dai *codec_dai; int i; #endif mutex_lock(&codec->mutex); - soc_cleanup_codec_debugfs(socdev->codec); + soc_cleanup_codec_debugfs(codec); #ifdef CONFIG_SND_SOC_AC97_BUS for (i = 0; i < codec->num_dai; i++) { codec_dai = &codec->dai[i]; - if (codec_dai->ac97_control && codec->ac97) { + if (codec_dai->ac97_control && codec->ac97 && + strcmp(codec->name, "AC97") != 0) { soc_ac97_dev_unregister(codec); goto free_card; } @@ -1498,6 +1509,37 @@ struct snd_kcontrol *snd_soc_cnew(const struct snd_kcontrol_new *_template, EXPORT_SYMBOL_GPL(snd_soc_cnew); /** + * snd_soc_add_controls - add an array of controls to a codec. + * Convienience function to add a list of controls. Many codecs were + * duplicating this code. + * + * @codec: codec to add controls to + * @controls: array of controls to add + * @num_controls: number of elements in the array + * + * Return 0 for success, else error. + */ +int snd_soc_add_controls(struct snd_soc_codec *codec, + const struct snd_kcontrol_new *controls, int num_controls) +{ + struct snd_card *card = codec->card; + int err, i; + + for (i = 0; i < num_controls; i++) { + const struct snd_kcontrol_new *control = &controls[i]; + err = snd_ctl_add(card, snd_soc_cnew(control, codec, NULL)); + if (err < 0) { + dev_err(codec->dev, "%s: Failed to add %s\n", + codec->name, control->name); + return err; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_add_controls); + +/** * snd_soc_info_enum_double - enumerated double mixer info callback * @kcontrol: mixer control * @uinfo: control element information @@ -2023,8 +2065,8 @@ EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8); int snd_soc_dai_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int freq, int dir) { - if (dai->ops.set_sysclk) - return dai->ops.set_sysclk(dai, clk_id, freq, dir); + if (dai->ops->set_sysclk) + return dai->ops->set_sysclk(dai, clk_id, freq, dir); else return -EINVAL; } @@ -2043,8 +2085,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_sysclk); int snd_soc_dai_set_clkdiv(struct snd_soc_dai *dai, int div_id, int div) { - if (dai->ops.set_clkdiv) - return dai->ops.set_clkdiv(dai, div_id, div); + if (dai->ops->set_clkdiv) + return dai->ops->set_clkdiv(dai, div_id, div); else return -EINVAL; } @@ -2062,8 +2104,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_clkdiv); int snd_soc_dai_set_pll(struct snd_soc_dai *dai, int pll_id, unsigned int freq_in, unsigned int freq_out) { - if (dai->ops.set_pll) - return dai->ops.set_pll(dai, pll_id, freq_in, freq_out); + if (dai->ops->set_pll) + return dai->ops->set_pll(dai, pll_id, freq_in, freq_out); else return -EINVAL; } @@ -2078,8 +2120,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_pll); */ int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - if (dai->ops.set_fmt) - return dai->ops.set_fmt(dai, fmt); + if (dai->ops->set_fmt) + return dai->ops->set_fmt(dai, fmt); else return -EINVAL; } @@ -2097,8 +2139,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_fmt); int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai, unsigned int mask, int slots) { - if (dai->ops.set_sysclk) - return dai->ops.set_tdm_slot(dai, mask, slots); + if (dai->ops->set_sysclk) + return dai->ops->set_tdm_slot(dai, mask, slots); else return -EINVAL; } @@ -2113,8 +2155,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tdm_slot); */ int snd_soc_dai_set_tristate(struct snd_soc_dai *dai, int tristate) { - if (dai->ops.set_sysclk) - return dai->ops.set_tristate(dai, tristate); + if (dai->ops->set_sysclk) + return dai->ops->set_tristate(dai, tristate); else return -EINVAL; } @@ -2129,8 +2171,8 @@ EXPORT_SYMBOL_GPL(snd_soc_dai_set_tristate); */ int snd_soc_dai_digital_mute(struct snd_soc_dai *dai, int mute) { - if (dai->ops.digital_mute) - return dai->ops.digital_mute(dai, mute); + if (dai->ops->digital_mute) + return dai->ops->digital_mute(dai, mute); else return -EINVAL; } @@ -2183,6 +2225,9 @@ static int snd_soc_unregister_card(struct snd_soc_card *card) return 0; } +static struct snd_soc_dai_ops null_dai_ops = { +}; + /** * snd_soc_register_dai - Register a DAI with the ASoC core * @@ -2197,6 +2242,9 @@ int snd_soc_register_dai(struct snd_soc_dai *dai) if (!dai->dev) printk(KERN_WARNING "No device for DAI %s\n", dai->name); + if (!dai->ops) + dai->ops = &null_dai_ops; + INIT_LIST_HEAD(&dai->list); mutex_lock(&client_mutex);