ALSA: hda - Add power on/off counter
authorTakashi Iwai <tiwai@suse.de>
Wed, 11 Nov 2009 08:34:25 +0000 (09:34 +0100)
committerTakashi Iwai <tiwai@suse.de>
Wed, 11 Nov 2009 08:37:08 +0000 (09:37 +0100)
Added the power on/off counter and expose via sysfs files.
The sysfs files, power_on_acct and power_off_acct, are created under
each codec hwdep sysfs directory (e.g. /sys/class/sound/hwC0D0).
The files show the msec length of the codec power-on and power-off,
respectively.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/hda_codec.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_local.h

index 2b787b013e93f4ba63387098568f2ab29798c0fb..444d9039c1ace6df37ae3f7b1cb1d77f6b6a0e6f 100644 (file)
@@ -515,6 +515,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device)
        struct hda_codec *codec;
        list_for_each_entry(codec, &bus->codec_list, list) {
                snd_hda_hwdep_add_sysfs(codec);
+               snd_hda_hwdep_add_power_sysfs(codec);
        }
        return 0;
 }
@@ -2452,9 +2453,11 @@ static void hda_call_codec_suspend(struct hda_codec *codec)
                            codec->afg ? codec->afg : codec->mfg,
                            AC_PWRST_D3);
 #ifdef CONFIG_SND_HDA_POWER_SAVE
+       snd_hda_update_power_acct(codec);
        cancel_delayed_work(&codec->power_work);
        codec->power_on = 0;
        codec->power_transition = 0;
+       codec->power_jiffies = jiffies;
 #endif
 }
 
@@ -3191,6 +3194,17 @@ static void hda_keep_power_on(struct hda_codec *codec)
 {
        codec->power_count++;
        codec->power_on = 1;
+       codec->power_jiffies = jiffies;
+}
+
+void snd_hda_update_power_acct(struct hda_codec *codec)
+{
+       unsigned long delta = jiffies - codec->power_jiffies;
+       if (codec->power_on)
+               codec->power_on_acct += delta;
+       else
+               codec->power_off_acct += delta;
+       codec->power_jiffies += delta;
 }
 
 void snd_hda_power_up(struct hda_codec *codec)
@@ -3201,7 +3215,9 @@ void snd_hda_power_up(struct hda_codec *codec)
        if (codec->power_on || codec->power_transition)
                return;
 
+       snd_hda_update_power_acct(codec);
        codec->power_on = 1;
+       codec->power_jiffies = jiffies;
        if (bus->ops.pm_notify)
                bus->ops.pm_notify(bus);
        hda_call_codec_resume(codec);
index cbf199a98ab2738faeabf9553d86ecaa912f900d..b16678cade18ce3ebb2f0f470c94519ac7934a13 100644 (file)
@@ -812,6 +812,9 @@ struct hda_codec {
        unsigned int power_transition :1; /* power-state in transition */
        int power_count;        /* current (global) power refcount */
        struct delayed_work power_work; /* delayed task for powerdown */
+       unsigned long power_on_acct;
+       unsigned long power_off_acct;
+       unsigned long power_jiffies;
 #endif
 
        /* codec-specific additional proc output */
@@ -936,6 +939,7 @@ const char *snd_hda_get_jack_location(u32 cfg);
 void snd_hda_power_up(struct hda_codec *codec);
 void snd_hda_power_down(struct hda_codec *codec);
 #define snd_hda_codec_needs_resume(codec) codec->power_count
+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_down(struct hda_codec *codec) {}
index cc24e6721d74ad12516595a1cf7904a51bc3fa55..d24328661c6a8f27a935f244d31234726fd906df 100644 (file)
@@ -154,6 +154,44 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec)
        return 0;
 }
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+static ssize_t power_on_acct_show(struct device *dev,
+                                 struct device_attribute *attr,
+                                 char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       snd_hda_update_power_acct(codec);
+       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct));
+}
+
+static ssize_t power_off_acct_show(struct device *dev,
+                                  struct device_attribute *attr,
+                                  char *buf)
+{
+       struct snd_hwdep *hwdep = dev_get_drvdata(dev);
+       struct hda_codec *codec = hwdep->private_data;
+       snd_hda_update_power_acct(codec);
+       return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct));
+}
+
+static struct device_attribute power_attrs[] = {
+       __ATTR_RO(power_on_acct),
+       __ATTR_RO(power_off_acct),
+};
+
+int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
+{
+       struct snd_hwdep *hwdep = codec->hwdep;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(power_attrs); i++)
+               snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card,
+                                         hwdep->device, &power_attrs[i]);
+       return 0;
+}
+#endif /* CONFIG_SND_HDA_POWER_SAVE */
+
 #ifdef CONFIG_SND_HDA_RECONFIG
 
 /*
index 461e0c15c77ab38cc351f062962cb632ef0a50ad..015fbac914b3dc03b71c0991fd9177993edcd3c8 100644 (file)
@@ -437,6 +437,15 @@ int snd_hda_create_hwdep(struct hda_codec *codec);
 static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; }
 #endif
 
+#ifdef CONFIG_SND_HDA_POWER_SAVE
+int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec);
+#else
+static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec)
+{
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_SND_HDA_RECONFIG
 int snd_hda_hwdep_add_sysfs(struct hda_codec *codec);
 #else