Commit a5e7e07c authored by Mengdong Lin's avatar Mengdong Lin Committed by Takashi Iwai

ALSA: hda - allow a codec to control the link power

A flag "link_power_control" is added to indicate whether a codec needs to
control the link power.  And a new bus ops link_power() is defined for the
codec to request to enable/disable the link power.
Signed-off-by: default avatarMengdong Lin <mengdong.lin@intel.com>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent d4b7b13e
...@@ -74,6 +74,7 @@ struct hdac_device { ...@@ -74,6 +74,7 @@ struct hdac_device {
/* misc flags */ /* misc flags */
atomic_t in_pm; /* suspend/resume being performed */ atomic_t in_pm; /* suspend/resume being performed */
bool link_power_control:1;
/* sysfs */ /* sysfs */
struct hdac_widget_tree *widgets; struct hdac_widget_tree *widgets;
...@@ -184,6 +185,8 @@ struct hdac_bus_ops { ...@@ -184,6 +185,8 @@ struct hdac_bus_ops {
/* get a response from the last command */ /* get a response from the last command */
int (*get_response)(struct hdac_bus *bus, unsigned int addr, int (*get_response)(struct hdac_bus *bus, unsigned int addr,
unsigned int *res); unsigned int *res);
/* control the link power */
int (*link_power)(struct hdac_bus *bus, bool enable);
}; };
/* /*
...@@ -311,6 +314,7 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec) ...@@ -311,6 +314,7 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val); int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr, int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
unsigned int *res); unsigned int *res);
int snd_hdac_link_power(struct hdac_device *codec, bool enable);
bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset); bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
void snd_hdac_bus_stop_chip(struct hdac_bus *bus); void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
......
...@@ -552,6 +552,21 @@ void snd_hdac_power_down_pm(struct hdac_device *codec) ...@@ -552,6 +552,21 @@ void snd_hdac_power_down_pm(struct hdac_device *codec)
EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm); EXPORT_SYMBOL_GPL(snd_hdac_power_down_pm);
#endif #endif
/*
* Enable/disable the link power for a codec.
*/
int snd_hdac_link_power(struct hdac_device *codec, bool enable)
{
if (!codec->link_power_control)
return 0;
if (codec->bus->ops->link_power)
return codec->bus->ops->link_power(codec->bus, enable);
else
return -EINVAL;
}
EXPORT_SYMBOL_GPL(snd_hdac_link_power);
/* codec vendor labels */ /* codec vendor labels */
struct hda_vendor_id { struct hda_vendor_id {
unsigned int id; unsigned int id;
......
...@@ -857,6 +857,7 @@ void snd_hda_codec_register(struct hda_codec *codec) ...@@ -857,6 +857,7 @@ void snd_hda_codec_register(struct hda_codec *codec)
return; return;
if (device_is_registered(hda_codec_dev(codec))) { if (device_is_registered(hda_codec_dev(codec))) {
snd_hda_register_beep_device(codec); snd_hda_register_beep_device(codec);
snd_hdac_link_power(&codec->core, true);
pm_runtime_enable(hda_codec_dev(codec)); pm_runtime_enable(hda_codec_dev(codec));
/* it was powered up in snd_hda_codec_new(), now all done */ /* it was powered up in snd_hda_codec_new(), now all done */
snd_hda_power_down(codec); snd_hda_power_down(codec);
...@@ -883,6 +884,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device) ...@@ -883,6 +884,7 @@ static int snd_hda_codec_dev_free(struct snd_device *device)
struct hda_codec *codec = device->device_data; struct hda_codec *codec = device->device_data;
codec->in_freeing = 1; codec->in_freeing = 1;
snd_hdac_link_power(&codec->core, false);
snd_hdac_device_unregister(&codec->core); snd_hdac_device_unregister(&codec->core);
put_device(hda_codec_dev(codec)); put_device(hda_codec_dev(codec));
return 0; return 0;
...@@ -3102,6 +3104,7 @@ static int hda_codec_runtime_suspend(struct device *dev) ...@@ -3102,6 +3104,7 @@ static int hda_codec_runtime_suspend(struct device *dev)
if (codec_has_clkstop(codec) && codec_has_epss(codec) && if (codec_has_clkstop(codec) && codec_has_epss(codec) &&
(state & AC_PWRST_CLK_STOP_OK)) (state & AC_PWRST_CLK_STOP_OK))
snd_hdac_codec_link_down(&codec->core); snd_hdac_codec_link_down(&codec->core);
snd_hdac_link_power(&codec->core, false);
return 0; return 0;
} }
...@@ -3109,6 +3112,7 @@ static int hda_codec_runtime_resume(struct device *dev) ...@@ -3109,6 +3112,7 @@ static int hda_codec_runtime_resume(struct device *dev)
{ {
struct hda_codec *codec = dev_to_hda_codec(dev); struct hda_codec *codec = dev_to_hda_codec(dev);
snd_hdac_link_power(&codec->core, true);
snd_hdac_codec_link_up(&codec->core); snd_hdac_codec_link_up(&codec->core);
hda_call_codec_resume(codec); hda_call_codec_resume(codec);
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment