Browse Source

ALSA: hda - Implement snd_hda_power_sync() helper function

Added a new helper function snd_hda_power_sync() to trigger the
power-saving manually.  It's an inline function call to
snd_hda_power_save() helper function.

Together with this addition, snd_hda_power_up*() and
snd_hda_power_down() functions are inlined to a call of the same
snd_hda_power_save() helper function.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 13 years ago
parent
commit
c376e2c72b
2 changed files with 82 additions and 60 deletions
  1. 28 54
      sound/pci/hda/hda_codec.c
  2. 54 6
      sound/pci/hda/hda_codec.h

+ 28 - 54
sound/pci/hda/hda_codec.c

@@ -4411,20 +4411,16 @@ void snd_hda_update_power_acct(struct hda_codec *codec)
 /* Transition to powered up, if wait_power_down then wait for a pending
  * transition to D3 to complete. A pending D3 transition is indicated
  * with power_transition == -1. */
+/* call this with codec->power_lock held! */
 static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
 {
 	struct hda_bus *bus = codec->bus;
 
-	spin_lock(&codec->power_lock);
-	codec->power_count++;
-	trace_hda_power_count(codec);
 	/* Return if power_on or transitioning to power_on, unless currently
 	 * powering down. */
 	if ((codec->power_on || codec->power_transition > 0) &&
-	    !(wait_power_down && codec->power_transition < 0)) {
-		spin_unlock(&codec->power_lock);
+	    !(wait_power_down && codec->power_transition < 0))
 		return;
-	}
 	spin_unlock(&codec->power_lock);
 
 	cancel_delayed_work_sync(&codec->power_work);
@@ -4433,10 +4429,9 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
 	/* If the power down delayed work was cancelled above before starting,
 	 * then there is no need to go through power up here.
 	 */
-	if (codec->power_on) {
-		spin_unlock(&codec->power_lock);
+	if (codec->power_on)
 		return;
-	}
+
 	trace_hda_power_up(codec);
 	snd_hda_update_power_acct(codec);
 	codec->power_on = 1;
@@ -4450,66 +4445,45 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down)
 
 	spin_lock(&codec->power_lock);
 	codec->power_transition = 0;
-	spin_unlock(&codec->power_lock);
 }
 
-/**
- * snd_hda_power_up - Power-up the codec
- * @codec: HD-audio codec
- *
- * Increment the power-up counter and power up the hardware really when
- * not turned on yet.
- */
-void snd_hda_power_up(struct hda_codec *codec)
-{
-	__snd_hda_power_up(codec, false);
-}
-EXPORT_SYMBOL_HDA(snd_hda_power_up);
+#define power_save(codec)	\
+	((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
 
-/**
- * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
- *   D3 transition to complete.  This differs from snd_hda_power_up() when
- *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
- *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
- *   back up.
- * @codec: HD-audio codec
- *
- * Cancel any power down operation hapenning on the work queue, then power up.
- */
-void snd_hda_power_up_d3wait(struct hda_codec *codec)
+/* Transition to powered down */
+static void __snd_hda_power_down(struct hda_codec *codec)
 {
-	/* This will cancel and wait for pending power_work to complete. */
-	__snd_hda_power_up(codec, true);
-}
-EXPORT_SYMBOL_HDA(snd_hda_power_up_d3wait);
+	if (!codec->power_on || codec->power_count || codec->power_transition)
+		return;
 
-#define power_save(codec)	\
-	((codec)->bus->power_save ? *(codec)->bus->power_save : 0)
+	if (power_save(codec)) {
+		codec->power_transition = -1; /* avoid reentrance */
+		queue_delayed_work(codec->bus->workq, &codec->power_work,
+				msecs_to_jiffies(power_save(codec) * 1000));
+	}
+}
 
 /**
- * snd_hda_power_down - Power-down the codec
+ * snd_hda_power_save - Power-up/down/sync the codec
  * @codec: HD-audio codec
+ * @delta: the counter delta to change
  *
- * Decrement the power-up counter and schedules the power-off work if
- * the counter rearches to zero.
+ * Change the power-up counter via @delta, and power up or down the hardware
+ * appropriately.  For the power-down, queue to the delayed action.
+ * Passing zero to @delta means to synchronize the power state.
  */
-void snd_hda_power_down(struct hda_codec *codec)
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait)
 {
 	spin_lock(&codec->power_lock);
-	--codec->power_count;
+	codec->power_count += delta;
 	trace_hda_power_count(codec);
-	if (!codec->power_on || codec->power_count || codec->power_transition) {
-		spin_unlock(&codec->power_lock);
-		return;
-	}
-	if (power_save(codec)) {
-		codec->power_transition = -1; /* avoid reentrance */
-		queue_delayed_work(codec->bus->workq, &codec->power_work,
-				msecs_to_jiffies(power_save(codec) * 1000));
-	}
+	if (delta > 0)
+		__snd_hda_power_up(codec, d3wait);
+	else
+		__snd_hda_power_down(codec);
 	spin_unlock(&codec->power_lock);
 }
-EXPORT_SYMBOL_HDA(snd_hda_power_down);
+EXPORT_SYMBOL_HDA(snd_hda_power_save);
 
 /**
  * snd_hda_check_amp_list_power - Check the amp list and update the power

+ 54 - 6
sound/pci/hda/hda_codec.h

@@ -1062,16 +1062,64 @@ const char *snd_hda_get_jack_location(u32 cfg);
  * power saving
  */
 #ifdef CONFIG_SND_HDA_POWER_SAVE
-void snd_hda_power_up(struct hda_codec *codec);
-void snd_hda_power_up_d3wait(struct hda_codec *codec);
-void snd_hda_power_down(struct hda_codec *codec);
+void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait);
 void snd_hda_update_power_acct(struct hda_codec *codec);
 #else
-static inline void snd_hda_power_up(struct hda_codec *codec) {}
-static inline void snd_hda_power_up_d3wait(struct hda_codec *codec) {}
-static inline void snd_hda_power_down(struct hda_codec *codec) {}
+static inline void snd_hda_power_save(struct hda_codec *codec, int delta,
+				      bool d3wait) {}
 #endif
 
+/**
+ * snd_hda_power_up - Power-up the codec
+ * @codec: HD-audio codec
+ *
+ * Increment the power-up counter and power up the hardware really when
+ * not turned on yet.
+ */
+static inline void snd_hda_power_up(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, 1, false);
+}
+
+/**
+ * snd_hda_power_up_d3wait - Power-up the codec after waiting for any pending
+ *   D3 transition to complete.  This differs from snd_hda_power_up() when
+ *   power_transition == -1.  snd_hda_power_up sees this case as a nop,
+ *   snd_hda_power_up_d3wait waits for the D3 transition to complete then powers
+ *   back up.
+ * @codec: HD-audio codec
+ *
+ * Cancel any power down operation hapenning on the work queue, then power up.
+ */
+static inline void snd_hda_power_up_d3wait(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, 1, true);
+}
+
+/**
+ * snd_hda_power_down - Power-down the codec
+ * @codec: HD-audio codec
+ *
+ * Decrement the power-up counter and schedules the power-off work if
+ * the counter rearches to zero.
+ */
+static inline void snd_hda_power_down(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, -1, false);
+}
+
+/**
+ * snd_hda_power_sync - Synchronize the power-save status
+ * @codec: HD-audio codec
+ *
+ * Synchronize the actual power state with the power account;
+ * called when power_save parameter is changed
+ */
+static inline void snd_hda_power_sync(struct hda_codec *codec)
+{
+	snd_hda_power_save(codec, 0, false);
+}
+
 #ifdef CONFIG_SND_HDA_PATCH_LOADER
 /*
  * patch firmware