/* * hdac_hda.c - ASoC extensions to reuse the legacy HDA codec drivers * with ASoC platform drivers. These APIs are called by the legacy HDA * codec drivers using hdac_ext_bus_ops ops.
*/
module_param_array_named(patch, loadable_patch, charp, NULL, 0444);
MODULE_PARM_DESC(patch, "Patch file array for Intel HD audio interface. The array index is the codec address."); #endif
/* * map DAI ID to the closest matching PCM name, using the naming * scheme used by hda-codec snd_hda_gen_build_pcms() and for * HDMI in hda_codec patch_hdmi.c)
*/
switch (dai->id) { case HDAC_ANALOG_DAI_ID:
pcm_name = "Analog"; break; case HDAC_DIGITAL_DAI_ID:
pcm_name = "Digital"; break; case HDAC_ALT_ANALOG_DAI_ID:
pcm_name = "Alt Analog"; break; case HDAC_HDMI_0_DAI_ID:
pcm_name = "HDMI 0"; break; case HDAC_HDMI_1_DAI_ID:
pcm_name = "HDMI 1"; break; case HDAC_HDMI_2_DAI_ID:
pcm_name = "HDMI 2"; break; case HDAC_HDMI_3_DAI_ID:
pcm_name = "HDMI 3"; break; default:
dev_err(dai->dev, "%s: invalid dai id %d\n", __func__, dai->id); return NULL;
}
list_for_each_entry(cpcm, &hcodec->pcm_list_head, list) { if (strstr(cpcm->name, pcm_name)) { if (strcmp(pcm_name, "Analog") == 0) { if (strstr(cpcm->name, "Alt Analog")) continue;
} return cpcm;
}
}
dev_err(dai->dev, "%s: didn't find PCM for DAI %s\n", __func__, dai->name); return NULL;
}
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) {
dev_err(&hdev->dev, "%s: hdac link not found\n", __func__); return -EIO;
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
/* * Ensure any HDA display is powered at codec probe. * After snd_hda_codec_device_new(), display power is * managed by runtime PM.
*/ if (hda_pvt->need_display_power)
snd_hdac_display_power(hdev->bus,
HDA_CODEC_IDX_CONTROLLER, true);
ret = snd_hda_codec_device_new(hcodec->bus, component->card->snd_card,
hdev->addr, hcodec, true); if (ret < 0) {
dev_err(&hdev->dev, "%s: failed to create hda codec %d\n", __func__, ret); goto error_no_pm;
}
#ifdef CONFIG_SND_HDA_PATCH_LOADER if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) { conststruct firmware *fw;
dev_info(&hdev->dev, "Applying patch firmware '%s'\n",
loadable_patch[hda_pvt->dev_index]);
ret = request_firmware(&fw, loadable_patch[hda_pvt->dev_index],
&hdev->dev); if (ret < 0) goto error_no_pm; if (fw) {
ret = snd_hda_load_patch(hcodec->bus, fw->size, fw->data); if (ret < 0) {
dev_err(&hdev->dev, "%s: failed to load hda patch %d\n", __func__, ret); goto error_no_pm;
}
release_firmware(fw);
}
} #endif /* * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver * hda_codec.c will check this flag to determine if unregister * device is needed.
*/
hdev->type = HDA_DEV_ASOC;
/* * snd_hda_codec_device_new decrements the usage count so call get pm * else the device will be powered off
*/
pm_runtime_get_noresume(&hdev->dev);
hcodec->bus->card = dapm->card->snd_card;
ret = snd_hda_codec_set_name(hcodec, hcodec->preset->name); if (ret < 0) {
dev_err(&hdev->dev, "%s: name failed %s\n", __func__, hcodec->preset->name); goto error_pm;
}
ret = snd_hdac_regmap_init(&hcodec->core); if (ret < 0) {
dev_err(&hdev->dev, "%s: regmap init failed\n", __func__); goto error_pm;
}
if (WARN_ON(!(driver->ops && driver->ops->probe))) {
ret = -EINVAL; goto error_regmap;
}
ret = driver->ops->probe(hcodec, hcodec->preset); if (ret < 0) {
dev_err(&hdev->dev, "%s: probe failed %d\n", __func__, ret); goto error_regmap;
}
ret = snd_hda_codec_parse_pcms(hcodec); if (ret < 0) {
dev_err(&hdev->dev, "%s: unable to map pcms to dai %d\n", __func__, ret); goto error_patch;
}
/* HDMI controls need to be created in machine drivers */ if (!is_hdmi_codec(hcodec)) {
ret = snd_hda_codec_build_controls(hcodec); if (ret < 0) {
dev_err(&hdev->dev, "%s: unable to create controls %d\n",
__func__, ret); goto error_patch;
}
}
hcodec->core.lazy_cache = true;
if (hda_pvt->need_display_power)
snd_hdac_display_power(hdev->bus,
HDA_CODEC_IDX_CONTROLLER, false);
/* match for forbid call in snd_hda_codec_device_new() */
pm_runtime_allow(&hdev->dev);
/* * hdac_device core already sets the state to active and calls * get_noresume. So enable runtime and set the device to suspend. * pm_runtime_enable is also called during codec registeration
*/
pm_runtime_put(&hdev->dev);
pm_runtime_suspend(&hdev->dev);
/* hold the ref while we probe */
hlink = snd_hdac_ext_bus_get_hlink_by_name(hdev->bus, dev_name(&hdev->dev)); if (!hlink) {
dev_err(&hdev->dev, "%s: hdac link not found\n", __func__); return -EIO;
}
snd_hdac_ext_bus_link_get(hdev->bus, hlink);
/* ASoC specific initialization */ if (hda_pvt->need_display_power)
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_hdmi_codec, hdac_hda_hdmi_dais,
ARRAY_SIZE(hdac_hda_hdmi_dais)); else
ret = devm_snd_soc_register_component(&hdev->dev,
&hdac_hda_codec, hdac_hda_dais,
ARRAY_SIZE(hdac_hda_dais));
if (ret < 0) {
dev_err(&hdev->dev, "%s: failed to register HDA codec %d\n", __func__, ret); return ret;
}
snd_hdac_ext_bus_link_put(hdev->bus, hlink);
return ret;
}
staticint hdac_hda_dev_remove(struct hdac_device *hdev)
{ /* * Resources are freed in hdac_hda_codec_remove(). This * function is kept to keep hda_codec_driver_remove() happy.
*/ return 0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.