]> nv-tegra.nvidia Code Review - linux-3.10.git/blobdiff - sound/drivers/pcsp/pcsp.c
ALSA: convert PM ops of platform_driver to new pm ops
[linux-3.10.git] / sound / drivers / pcsp / pcsp.c
index 264d2a56dcd2ec738d835c7bd0d2e7964c81f09f..6ca59fc6dcb9c0faf3e5fe07890fd237568a5d79 100644 (file)
@@ -6,12 +6,13 @@
  */
 
 #include <linux/init.h>
-#include <linux/moduleparam.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <sound/core.h>
 #include <sound/initval.h>
 #include <sound/pcm.h>
 #include <linux/input.h>
+#include <linux/delay.h>
 #include <asm/bitops.h>
 #include "pcsp_input.h"
 #include "pcsp.h"
@@ -24,14 +25,17 @@ MODULE_ALIAS("platform:pcspkr");
 
 static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */
 static char *id = SNDRV_DEFAULT_STR1;  /* ID for this card */
-static int enable = SNDRV_DEFAULT_ENABLE1;     /* Enable this card */
+static bool enable = SNDRV_DEFAULT_ENABLE1;    /* Enable this card */
+static bool nopcm;     /* Disable PCM capability of the driver */
 
 module_param(index, int, 0444);
 MODULE_PARM_DESC(index, "Index value for pcsp soundcard.");
 module_param(id, charp, 0444);
 MODULE_PARM_DESC(id, "ID string for pcsp soundcard.");
 module_param(enable, bool, 0444);
-MODULE_PARM_DESC(enable, "dummy");
+MODULE_PARM_DESC(enable, "Enable PC-Speaker sound.");
+module_param(nopcm, bool, 0444);
+MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain.");
 
 struct snd_pcsp pcsp_chip;
 
@@ -42,13 +46,16 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
        int err;
        int div, min_div, order;
 
-       hrtimer_get_res(CLOCK_MONOTONIC, &tp);
-       if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
-               printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
-                      "(%linS)\n", tp.tv_nsec);
-               printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
-                      "enabled.\n");
-               return -EIO;
+       if (!nopcm) {
+               hrtimer_get_res(CLOCK_MONOTONIC, &tp);
+               if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) {
+                       printk(KERN_ERR "PCSP: Timer resolution is not sufficient "
+                               "(%linS)\n", tp.tv_nsec);
+                       printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI "
+                               "enabled.\n");
+                       printk(KERN_ERR "PCSP: Turned into nopcm mode.\n");
+                       nopcm = 1;
+               }
        }
 
        if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS)
@@ -56,7 +63,7 @@ static int __devinit snd_pcsp_create(struct snd_card *card)
        else
                min_div = MAX_DIV;
 #if PCSP_DEBUG
-       printk("PCSP: lpj=%li, min_div=%i, res=%li\n",
+       printk(KERN_DEBUG "PCSP: lpj=%li, min_div=%i, res=%li\n",
               loops_per_jiffy, min_div, tp.tv_nsec);
 #endif
 
@@ -95,24 +102,25 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
                return -EINVAL;
 
        hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-       pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE;
        pcsp_chip.timer.function = pcsp_do_timer;
 
-       card = snd_card_new(index, id, THIS_MODULE, 0);
-       if (!card)
-               return -ENOMEM;
+       err = snd_card_create(index, id, THIS_MODULE, 0, &card);
+       if (err < 0)
+               return err;
 
        err = snd_pcsp_create(card);
        if (err < 0) {
                snd_card_free(card);
                return err;
        }
-       err = snd_pcsp_new_pcm(&pcsp_chip);
-       if (err < 0) {
-               snd_card_free(card);
-               return err;
+       if (!nopcm) {
+               err = snd_pcsp_new_pcm(&pcsp_chip);
+               if (err < 0) {
+                       snd_card_free(card);
+                       return err;
+               }
        }
-       err = snd_pcsp_new_mixer(&pcsp_chip);
+       err = snd_pcsp_new_mixer(&pcsp_chip, nopcm);
        if (err < 0) {
                snd_card_free(card);
                return err;
@@ -136,27 +144,20 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
 
 static int __devinit alsa_card_pcsp_init(struct device *dev)
 {
-       int devnum = 0, cards = 0;
+       int err;
+
+       err = snd_card_pcsp_probe(0, dev);
+       if (err) {
+               printk(KERN_ERR "PC-Speaker initialization failed.\n");
+               return err;
+       }
 
 #ifdef CONFIG_DEBUG_PAGEALLOC
        /* Well, CONFIG_DEBUG_PAGEALLOC makes the sound horrible. Lets alert */
-       printk(KERN_WARNING
-              "PCSP: Warning, CONFIG_DEBUG_PAGEALLOC is enabled!\n"
-              "You have to disable it if you want to use the PC-Speaker "
-              "driver.\n"
-              "Unless it is disabled, enjoy the horrible, distorted "
-              "and crackling noise.\n");
+       printk(KERN_WARNING "PCSP: CONFIG_DEBUG_PAGEALLOC is enabled, "
+              "which may make the sound noisy.\n");
 #endif
 
-       if (enable) {
-               if (snd_card_pcsp_probe(devnum, dev) >= 0)
-                       cards++;
-               if (!cards) {
-                       printk(KERN_ERR "PC-Speaker initialization failed.\n");
-                       return -ENODEV;
-               }
-       }
-
        return 0;
 }
 
@@ -168,6 +169,7 @@ static void __devexit alsa_card_pcsp_exit(struct snd_pcsp *chip)
 static int __devinit pcsp_probe(struct platform_device *dev)
 {
        int err;
+
        err = pcspkr_input_init(&pcsp_chip.input_dev, &dev->dev);
        if (err < 0)
                return err;
@@ -193,21 +195,25 @@ static int __devexit pcsp_remove(struct platform_device *dev)
 
 static void pcsp_stop_beep(struct snd_pcsp *chip)
 {
-       unsigned long flags;
-       spin_lock_irqsave(&chip->substream_lock, flags);
-       if (!chip->playback_substream)
-               pcspkr_stop_sound();
-       spin_unlock_irqrestore(&chip->substream_lock, flags);
+       pcsp_sync_stop(chip);
+       pcspkr_stop_sound();
 }
 
-static int pcsp_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM
+static int pcsp_suspend(struct device *dev)
 {
-       struct snd_pcsp *chip = platform_get_drvdata(dev);
+       struct snd_pcsp *chip = dev_get_drvdata(dev);
        pcsp_stop_beep(chip);
        snd_pcm_suspend_all(chip->pcm);
        return 0;
 }
 
+static SIMPLE_DEV_PM_OPS(pcsp_pm, pcsp_suspend, NULL);
+#define PCSP_PM_OPS    &pcsp_pm
+#else
+#define PCSP_PM_OPS    NULL
+#endif /* CONFIG_PM */
+
 static void pcsp_shutdown(struct platform_device *dev)
 {
        struct snd_pcsp *chip = platform_get_drvdata(dev);
@@ -218,15 +224,17 @@ static struct platform_driver pcsp_platform_driver = {
        .driver         = {
                .name   = "pcspkr",
                .owner  = THIS_MODULE,
+               .pm     = PCSP_PM_OPS,
        },
        .probe          = pcsp_probe,
        .remove         = __devexit_p(pcsp_remove),
-       .suspend        = pcsp_suspend,
        .shutdown       = pcsp_shutdown,
 };
 
 static int __init pcsp_init(void)
 {
+       if (!enable)
+               return -ENODEV;
        return platform_driver_register(&pcsp_platform_driver);
 }