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: Mengdong Lin <mengdong.lin@intel.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>hifive-unleashed-5.1
parent
d4b7b13e19
commit
a5e7e07c26
|
@ -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 {
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
{
|
{
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue