Loading include/sound/hdaudio_ext.h +13 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * @gtscap: gts capabilities pointer * @drsmcap: dma resume capabilities pointer * @hlink_list: link list of HDA links * @lock: lock for link mgmt * @cmd_dma_state: state of cmd DMAs: CORB and RIRB */ struct hdac_ext_bus { struct hdac_bus bus; Loading @@ -27,6 +29,9 @@ struct hdac_ext_bus { void __iomem *drsmcap; struct list_head hlink_list; struct mutex lock; bool cmd_dma_state; }; int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev, Loading Loading @@ -142,6 +147,9 @@ struct hdac_ext_link { void __iomem *ml_addr; /* link output stream reg pointer */ u32 lcaps; /* link capablities */ u16 lsdiid; /* link sdi identifier */ int ref_count; struct list_head list; }; Loading @@ -154,6 +162,11 @@ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, int stream); int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, struct hdac_ext_link *link); int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, struct hdac_ext_link *link); /* update register macro */ #define snd_hdac_updatel(addr, reg, mask, val) \ writel(((readl(addr + reg) & ~(mask)) | (val)), \ Loading include/sound/soc.h +1 −1 Original line number Diff line number Diff line Loading @@ -1002,7 +1002,7 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; int be_id; /* optional ID for machine driver BE identification */ int id; /* optional ID for machine driver link identification */ const struct snd_soc_pcm_stream *params; unsigned int num_params; Loading sound/hda/ext/hdac_ext_bus.c +3 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev, INIT_LIST_HEAD(&ebus->hlink_list); ebus->idx = idx++; mutex_init(&ebus->lock); ebus->cmd_dma_state = true; return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); Loading sound/hda/ext/hdac_ext_controller.c +66 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); /* since link in On, update the ref */ hlink->ref_count = 1; list_add_tail(&hlink->list, &ebus->hlink_list); } Loading Loading @@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus) return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, struct hdac_ext_link *link) { int ret = 0; mutex_lock(&ebus->lock); /* * if we move from 0 to 1, count will be 1 so power up this link * as well, also check the dma status and trigger that */ if (++link->ref_count == 1) { if (!ebus->cmd_dma_state) { snd_hdac_bus_init_cmd_io(&ebus->bus); ebus->cmd_dma_state = true; } ret = snd_hdac_ext_bus_link_power_up(link); } mutex_unlock(&ebus->lock); return ret; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, struct hdac_ext_link *link) { int ret = 0; struct hdac_ext_link *hlink; bool link_up = false; mutex_lock(&ebus->lock); /* * if we move from 1 to 0, count will be 0 * so power down this link as well */ if (--link->ref_count == 0) { ret = snd_hdac_ext_bus_link_power_down(link); /* * now check if all links are off, if so turn off * cmd dma as well */ list_for_each_entry(hlink, &ebus->hlink_list, list) { if (hlink->ref_count) { link_up = true; break; } } if (!link_up) { snd_hdac_bus_stop_cmd_io(&ebus->bus); ebus->cmd_dma_state = false; } } mutex_unlock(&ebus->lock); return ret; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put); sound/soc/codecs/hdac_hdmi.c +30 −2 Original line number Diff line number Diff line Loading @@ -1378,10 +1378,18 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; int ret; edev->scodec = codec; /* * hold the ref while we probe, also no need to drop the ref on * exit, we call pm_runtime_suspend() so that will do for us */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); snd_hdac_ext_bus_link_get(edev->ebus, hlink); ret = create_fill_widget_route_map(dapm); if (ret < 0) return ret; Loading Loading @@ -1480,9 +1488,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) struct hdac_device *codec = &edev->hdac; struct hdac_hdmi_priv *hdmi_priv; struct snd_soc_dai_driver *hdmi_dais = NULL; struct hdac_ext_link *hlink = NULL; int num_dais = 0; int ret = 0; /* hold the ref while we probe */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); snd_hdac_ext_bus_link_get(edev->ebus, hlink); hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); if (hdmi_priv == NULL) return -ENOMEM; Loading Loading @@ -1516,8 +1529,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) } /* ASoC specific initialization */ return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, hdmi_dais, num_dais); snd_hdac_ext_bus_link_put(edev->ebus, hlink); return ret; } static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) Loading Loading @@ -1556,6 +1573,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; struct hdac_bus *bus = hdac->bus; unsigned long timeout; struct hdac_ext_bus *ebus = hbus_to_ebus(bus); struct hdac_ext_link *hlink = NULL; int err; dev_dbg(dev, "Enter: %s\n", __func__); Loading @@ -1579,6 +1599,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) return err; } hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); snd_hdac_ext_bus_link_put(ebus, hlink); return 0; } Loading @@ -1587,6 +1610,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev) struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; struct hdac_bus *bus = hdac->bus; struct hdac_ext_bus *ebus = hbus_to_ebus(bus); struct hdac_ext_link *hlink = NULL; int err; dev_dbg(dev, "Enter: %s\n", __func__); Loading @@ -1595,6 +1620,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev) if (!bus) return 0; hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); snd_hdac_ext_bus_link_get(ebus, hlink); err = snd_hdac_display_power(bus, true); if (err < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); Loading Loading
include/sound/hdaudio_ext.h +13 −0 Original line number Diff line number Diff line Loading @@ -14,6 +14,8 @@ * @gtscap: gts capabilities pointer * @drsmcap: dma resume capabilities pointer * @hlink_list: link list of HDA links * @lock: lock for link mgmt * @cmd_dma_state: state of cmd DMAs: CORB and RIRB */ struct hdac_ext_bus { struct hdac_bus bus; Loading @@ -27,6 +29,9 @@ struct hdac_ext_bus { void __iomem *drsmcap; struct list_head hlink_list; struct mutex lock; bool cmd_dma_state; }; int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev, Loading Loading @@ -142,6 +147,9 @@ struct hdac_ext_link { void __iomem *ml_addr; /* link output stream reg pointer */ u32 lcaps; /* link capablities */ u16 lsdiid; /* link sdi identifier */ int ref_count; struct list_head list; }; Loading @@ -154,6 +162,11 @@ void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link, void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link, int stream); int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, struct hdac_ext_link *link); int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, struct hdac_ext_link *link); /* update register macro */ #define snd_hdac_updatel(addr, reg, mask, val) \ writel(((readl(addr + reg) & ~(mask)) | (val)), \ Loading
include/sound/soc.h +1 −1 Original line number Diff line number Diff line Loading @@ -1002,7 +1002,7 @@ struct snd_soc_dai_link { */ const char *platform_name; struct device_node *platform_of_node; int be_id; /* optional ID for machine driver BE identification */ int id; /* optional ID for machine driver link identification */ const struct snd_soc_pcm_stream *params; unsigned int num_params; Loading
sound/hda/ext/hdac_ext_bus.c +3 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,9 @@ int snd_hdac_ext_bus_init(struct hdac_ext_bus *ebus, struct device *dev, INIT_LIST_HEAD(&ebus->hlink_list); ebus->idx = idx++; mutex_init(&ebus->lock); ebus->cmd_dma_state = true; return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_init); Loading
sound/hda/ext/hdac_ext_controller.c +66 −0 Original line number Diff line number Diff line Loading @@ -186,6 +186,9 @@ int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *ebus) hlink->lcaps = readl(hlink->ml_addr + AZX_REG_ML_LCAP); hlink->lsdiid = readw(hlink->ml_addr + AZX_REG_ML_LSDIID); /* since link in On, update the ref */ hlink->ref_count = 1; list_add_tail(&hlink->list, &ebus->hlink_list); } Loading Loading @@ -327,3 +330,66 @@ int snd_hdac_ext_bus_link_power_down_all(struct hdac_ext_bus *ebus) return 0; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_power_down_all); int snd_hdac_ext_bus_link_get(struct hdac_ext_bus *ebus, struct hdac_ext_link *link) { int ret = 0; mutex_lock(&ebus->lock); /* * if we move from 0 to 1, count will be 1 so power up this link * as well, also check the dma status and trigger that */ if (++link->ref_count == 1) { if (!ebus->cmd_dma_state) { snd_hdac_bus_init_cmd_io(&ebus->bus); ebus->cmd_dma_state = true; } ret = snd_hdac_ext_bus_link_power_up(link); } mutex_unlock(&ebus->lock); return ret; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_get); int snd_hdac_ext_bus_link_put(struct hdac_ext_bus *ebus, struct hdac_ext_link *link) { int ret = 0; struct hdac_ext_link *hlink; bool link_up = false; mutex_lock(&ebus->lock); /* * if we move from 1 to 0, count will be 0 * so power down this link as well */ if (--link->ref_count == 0) { ret = snd_hdac_ext_bus_link_power_down(link); /* * now check if all links are off, if so turn off * cmd dma as well */ list_for_each_entry(hlink, &ebus->hlink_list, list) { if (hlink->ref_count) { link_up = true; break; } } if (!link_up) { snd_hdac_bus_stop_cmd_io(&ebus->bus); ebus->cmd_dma_state = false; } } mutex_unlock(&ebus->lock); return ret; } EXPORT_SYMBOL_GPL(snd_hdac_ext_bus_link_put);
sound/soc/codecs/hdac_hdmi.c +30 −2 Original line number Diff line number Diff line Loading @@ -1378,10 +1378,18 @@ static int hdmi_codec_probe(struct snd_soc_codec *codec) struct snd_soc_dapm_context *dapm = snd_soc_component_get_dapm(&codec->component); struct hdac_hdmi_pin *pin; struct hdac_ext_link *hlink = NULL; int ret; edev->scodec = codec; /* * hold the ref while we probe, also no need to drop the ref on * exit, we call pm_runtime_suspend() so that will do for us */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); snd_hdac_ext_bus_link_get(edev->ebus, hlink); ret = create_fill_widget_route_map(dapm); if (ret < 0) return ret; Loading Loading @@ -1480,9 +1488,14 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) struct hdac_device *codec = &edev->hdac; struct hdac_hdmi_priv *hdmi_priv; struct snd_soc_dai_driver *hdmi_dais = NULL; struct hdac_ext_link *hlink = NULL; int num_dais = 0; int ret = 0; /* hold the ref while we probe */ hlink = snd_hdac_ext_bus_get_link(edev->ebus, dev_name(&edev->hdac.dev)); snd_hdac_ext_bus_link_get(edev->ebus, hlink); hdmi_priv = devm_kzalloc(&codec->dev, sizeof(*hdmi_priv), GFP_KERNEL); if (hdmi_priv == NULL) return -ENOMEM; Loading Loading @@ -1516,8 +1529,12 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev) } /* ASoC specific initialization */ return snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, ret = snd_soc_register_codec(&codec->dev, &hdmi_hda_codec, hdmi_dais, num_dais); snd_hdac_ext_bus_link_put(edev->ebus, hlink); return ret; } static int hdac_hdmi_dev_remove(struct hdac_ext_device *edev) Loading Loading @@ -1556,6 +1573,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; struct hdac_bus *bus = hdac->bus; unsigned long timeout; struct hdac_ext_bus *ebus = hbus_to_ebus(bus); struct hdac_ext_link *hlink = NULL; int err; dev_dbg(dev, "Enter: %s\n", __func__); Loading @@ -1579,6 +1599,9 @@ static int hdac_hdmi_runtime_suspend(struct device *dev) return err; } hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); snd_hdac_ext_bus_link_put(ebus, hlink); return 0; } Loading @@ -1587,6 +1610,8 @@ static int hdac_hdmi_runtime_resume(struct device *dev) struct hdac_ext_device *edev = to_hda_ext_device(dev); struct hdac_device *hdac = &edev->hdac; struct hdac_bus *bus = hdac->bus; struct hdac_ext_bus *ebus = hbus_to_ebus(bus); struct hdac_ext_link *hlink = NULL; int err; dev_dbg(dev, "Enter: %s\n", __func__); Loading @@ -1595,6 +1620,9 @@ static int hdac_hdmi_runtime_resume(struct device *dev) if (!bus) return 0; hlink = snd_hdac_ext_bus_get_link(ebus, dev_name(dev)); snd_hdac_ext_bus_link_get(ebus, hlink); err = snd_hdac_display_power(bus, true); if (err < 0) { dev_err(bus->dev, "Cannot turn on display power on i915\n"); Loading