Commit 55ed9cd1 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: hda - Replace bus pm_notify with the standard runtime PM framework

Now the final bit of runtime PM cleanup: instead of manual
notification of the power up/down of the codec via hda_bus pm_notify
ops, use the standard runtime PM feature.

The child codec device will kick off the runtime PM of the parent
(PCI) device upon suspend/resume automatically.  For managing whether
the link can be really turned off, we use the bit flags
bus->codec_powered instead of the earlier bus->power_keep_link_on.
flag.  Each codec driver is responsible to set/clear the bit flag, and
the controller device can be turned off only when all these bits are
cleared.
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent bb573928
...@@ -46,23 +46,9 @@ ...@@ -46,23 +46,9 @@
#define codec_in_pm(codec) atomic_read(&(codec)->in_pm) #define codec_in_pm(codec) atomic_read(&(codec)->in_pm)
#define hda_codec_is_power_on(codec) \ #define hda_codec_is_power_on(codec) \
(!pm_runtime_suspended(hda_codec_dev(codec))) (!pm_runtime_suspended(hda_codec_dev(codec)))
static void hda_call_pm_notify(struct hda_codec *codec, bool power_up)
{
struct hda_bus *bus = codec->bus;
if ((power_up && codec->pm_up_notified) ||
(!power_up && !codec->pm_up_notified))
return;
if (bus->ops.pm_notify)
bus->ops.pm_notify(bus, power_up);
codec->pm_up_notified = power_up;
}
#else #else
#define codec_in_pm(codec) 0 #define codec_in_pm(codec) 0
#define hda_codec_is_power_on(codec) 1 #define hda_codec_is_power_on(codec) 1
#define hda_call_pm_notify(codec, state) {}
#endif #endif
/** /**
...@@ -1152,7 +1138,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) ...@@ -1152,7 +1138,7 @@ static void snd_hda_codec_free(struct hda_codec *codec)
snd_array_free(&codec->spdif_out); snd_array_free(&codec->spdif_out);
remove_conn_list(codec); remove_conn_list(codec);
codec->bus->caddr_tbl[codec->addr] = NULL; codec->bus->caddr_tbl[codec->addr] = NULL;
hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ clear_bit(codec->addr, &codec->bus->codec_powered);
snd_hda_sysfs_clear(codec); snd_hda_sysfs_clear(codec);
free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->amp_cache);
free_hda_cache(&codec->cmd_cache); free_hda_cache(&codec->cmd_cache);
...@@ -1277,10 +1263,10 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1277,10 +1263,10 @@ int snd_hda_codec_new(struct hda_bus *bus,
* the caller has to power down appropriatley after initialization * the caller has to power down appropriatley after initialization
* phase. * phase.
*/ */
set_bit(codec->addr, &bus->codec_powered);
pm_runtime_set_active(hda_codec_dev(codec)); pm_runtime_set_active(hda_codec_dev(codec));
pm_runtime_get_noresume(hda_codec_dev(codec)); pm_runtime_get_noresume(hda_codec_dev(codec));
codec->power_jiffies = jiffies; codec->power_jiffies = jiffies;
hda_call_pm_notify(codec, true);
#endif #endif
snd_hda_sysfs_init(codec); snd_hda_sysfs_init(codec);
...@@ -1340,11 +1326,6 @@ int snd_hda_codec_new(struct hda_bus *bus, ...@@ -1340,11 +1326,6 @@ int snd_hda_codec_new(struct hda_bus *bus,
#endif #endif
codec->epss = snd_hda_codec_get_supported_ps(codec, fg, codec->epss = snd_hda_codec_get_supported_ps(codec, fg,
AC_PWRST_EPSS); AC_PWRST_EPSS);
#ifdef CONFIG_PM
if (!codec->d3_stop_clk || !codec->epss)
bus->power_keep_link_on = 1;
#endif
/* power-up all before initialization */ /* power-up all before initialization */
hda_set_power_state(codec, AC_PWRST_D0); hda_set_power_state(codec, AC_PWRST_D0);
...@@ -3954,7 +3935,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) ...@@ -3954,7 +3935,6 @@ static void hda_call_codec_resume(struct hda_codec *codec)
hda_mark_cmd_cache_dirty(codec); hda_mark_cmd_cache_dirty(codec);
codec->power_jiffies = jiffies; codec->power_jiffies = jiffies;
hda_call_pm_notify(codec, true);
hda_set_power_state(codec, AC_PWRST_D0); hda_set_power_state(codec, AC_PWRST_D0);
restore_shutup_pins(codec); restore_shutup_pins(codec);
...@@ -3986,14 +3966,17 @@ static int hda_codec_runtime_suspend(struct device *dev) ...@@ -3986,14 +3966,17 @@ static int hda_codec_runtime_suspend(struct device *dev)
for (i = 0; i < codec->num_pcms; i++) for (i = 0; i < codec->num_pcms; i++)
snd_pcm_suspend_all(codec->pcm_info[i].pcm); snd_pcm_suspend_all(codec->pcm_info[i].pcm);
state = hda_call_codec_suspend(codec); state = hda_call_codec_suspend(codec);
if (!codec->bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) if (codec->d3_stop_clk && codec->epss && (state & AC_PWRST_CLK_STOP_OK))
hda_call_pm_notify(codec, false); clear_bit(codec->addr, &codec->bus->codec_powered);
return 0; return 0;
} }
static int hda_codec_runtime_resume(struct device *dev) static int hda_codec_runtime_resume(struct device *dev)
{ {
hda_call_codec_resume(dev_to_hda_codec(dev)); struct hda_codec *codec = dev_to_hda_codec(dev);
set_bit(codec->addr, &codec->bus->codec_powered);
hda_call_codec_resume(codec);
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
return 0; return 0;
} }
......
...@@ -83,10 +83,6 @@ struct hda_bus_ops { ...@@ -83,10 +83,6 @@ struct hda_bus_ops {
struct hda_pcm *pcm); struct hda_pcm *pcm);
/* reset bus for retry verb */ /* reset bus for retry verb */
void (*bus_reset)(struct hda_bus *bus); void (*bus_reset)(struct hda_bus *bus);
#ifdef CONFIG_PM
/* notify power-up/down from codec to controller */
void (*pm_notify)(struct hda_bus *bus, bool power_up);
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER #ifdef CONFIG_SND_HDA_DSP_LOADER
/* prepare DSP transfer */ /* prepare DSP transfer */
int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format, int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format,
...@@ -150,10 +146,10 @@ struct hda_bus { ...@@ -150,10 +146,10 @@ struct hda_bus {
unsigned int rirb_error:1; /* error in codec communication */ unsigned int rirb_error:1; /* error in codec communication */
unsigned int response_reset:1; /* controller was reset */ unsigned int response_reset:1; /* controller was reset */
unsigned int in_reset:1; /* during reset operation */ unsigned int in_reset:1; /* during reset operation */
unsigned int power_keep_link_on:1; /* don't power off HDA link */
unsigned int no_response_fallback:1; /* don't fallback at RIRB error */ unsigned int no_response_fallback:1; /* don't fallback at RIRB error */
int primary_dig_out_type; /* primary digital out PCM type */ int primary_dig_out_type; /* primary digital out PCM type */
unsigned long codec_powered; /* bit flags of powered codecs */
}; };
/* /*
...@@ -372,7 +368,6 @@ struct hda_codec { ...@@ -372,7 +368,6 @@ struct hda_codec {
unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
#ifdef CONFIG_PM #ifdef CONFIG_PM
unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */
unsigned int pm_up_notified:1; /* PM notified to controller */
atomic_t in_pm; /* suspend/resume being performed */ atomic_t in_pm; /* suspend/resume being performed */
unsigned long power_on_acct; unsigned long power_on_acct;
unsigned long power_off_acct; unsigned long power_off_acct;
......
...@@ -1785,22 +1785,6 @@ static void azx_bus_reset(struct hda_bus *bus) ...@@ -1785,22 +1785,6 @@ static void azx_bus_reset(struct hda_bus *bus)
bus->in_reset = 0; bus->in_reset = 0;
} }
#ifdef CONFIG_PM
/* power-up/down the controller */
static void azx_power_notify(struct hda_bus *bus, bool power_up)
{
struct azx *chip = bus->private_data;
if (!azx_has_pm_runtime(chip))
return;
if (power_up)
pm_runtime_get_sync(chip->card->dev);
else
pm_runtime_put_sync(chip->card->dev);
}
#endif
static int get_jackpoll_interval(struct azx *chip) static int get_jackpoll_interval(struct azx *chip)
{ {
int i; int i;
...@@ -1827,9 +1811,6 @@ static struct hda_bus_ops bus_ops = { ...@@ -1827,9 +1811,6 @@ static struct hda_bus_ops bus_ops = {
.get_response = azx_get_response, .get_response = azx_get_response,
.attach_pcm = azx_attach_pcm_stream, .attach_pcm = azx_attach_pcm_stream,
.bus_reset = azx_bus_reset, .bus_reset = azx_bus_reset,
#ifdef CONFIG_PM
.pm_notify = azx_power_notify,
#endif
#ifdef CONFIG_SND_HDA_DSP_LOADER #ifdef CONFIG_SND_HDA_DSP_LOADER
.load_dsp_prepare = azx_load_dsp_prepare, .load_dsp_prepare = azx_load_dsp_prepare,
.load_dsp_trigger = azx_load_dsp_trigger, .load_dsp_trigger = azx_load_dsp_trigger,
......
...@@ -918,7 +918,8 @@ static int azx_runtime_idle(struct device *dev) ...@@ -918,7 +918,8 @@ static int azx_runtime_idle(struct device *dev)
if (chip->disabled || hda->init_failed) if (chip->disabled || hda->init_failed)
return 0; return 0;
if (!power_save_controller || !azx_has_pm_runtime(chip)) if (!power_save_controller || !azx_has_pm_runtime(chip) ||
chip->bus->codec_powered)
return -EBUSY; return -EBUSY;
return 0; return 0;
...@@ -1084,7 +1085,6 @@ static int azx_free(struct azx *chip) ...@@ -1084,7 +1085,6 @@ static int azx_free(struct azx *chip)
azx_stop_chip(chip); azx_stop_chip(chip);
} }
pci->dev.power.ignore_children = 0; /* FIXME */
if (chip->irq >= 0) if (chip->irq >= 0)
free_irq(chip->irq, (void*)chip); free_irq(chip->irq, (void*)chip);
if (chip->msi) if (chip->msi)
...@@ -1794,7 +1794,6 @@ static int azx_probe(struct pci_dev *pci, ...@@ -1794,7 +1794,6 @@ static int azx_probe(struct pci_dev *pci,
return err; return err;
} }
pci->dev.power.ignore_children = 1; /* FIXME */
err = azx_create(card, pci, dev, pci_id->driver_data, err = azx_create(card, pci, dev, pci_id->driver_data,
&pci_hda_ops, &chip); &pci_hda_ops, &chip);
if (err < 0) if (err < 0)
......
...@@ -2132,8 +2132,10 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, ...@@ -2132,8 +2132,10 @@ static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec,
if (action == HDA_FIXUP_ACT_PRE_PROBE) { if (action == HDA_FIXUP_ACT_PRE_PROBE) {
spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ spec->mic_mute_led_gpio = 0x08; /* GPIO3 */
#ifdef CONFIG_PM
/* resetting controller clears GPIO, so we need to keep on */ /* resetting controller clears GPIO, so we need to keep on */
codec->bus->power_keep_link_on = 1; codec->d3_stop_clk = 0;
#endif
} }
} }
......
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