]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Input: add ixp4xx beeper driver
authorAlessandro Zummo <alessandro.zummo@towertech.it>
Mon, 30 Jan 2006 02:50:40 +0000 (21:50 -0500)
committerDmitry Torokhov <dtor_core@ameritech.net>
Mon, 30 Jan 2006 02:50:40 +0000 (21:50 -0500)
This is a driver for beeper found in LinkSys NSLU2 boxes. It should work
on any ixp4xx based platform.

Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/ixp4xx-beeper.c [new file with mode: 0644]

index e08dbe08f46dd0100b7f31d1b3a82ce2e640b5c0..4bad588d0e5d6c53499aff9dbdb65dfc390aed35 100644 (file)
@@ -50,6 +50,18 @@ config INPUT_WISTRON_BTNS
          To compile this driver as a module, choose M here: the module will
          be called wistron_btns.
 
+config INPUT_IXP4XX_BEEPER
+       tristate "IXP4XX Beeper support"
+       depends on ARCH_IXP4XX
+       help
+         If you say yes here, you can connect a beeper to the
+         ixp4xx gpio pins. This is used by the LinkSys NSLU2.
+
+         If unsure, say Y.
+
+         To compile this driver as a module, choose M here: the
+         module will be called ixp4xx-beeper.
+
 config INPUT_UINPUT
        tristate "User level driver support"
        help
index ce44cce012855a22142eec77fcc83e38eb88b39e..184c4129470db801c2146d485ca98a95ac50b0fd 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_INPUT_98SPKR)            += 98spkr.o
 obj-$(CONFIG_INPUT_UINPUT)             += uinput.o
 obj-$(CONFIG_INPUT_WISTRON_BTNS)       += wistron_btns.o
 obj-$(CONFIG_HP_SDC_RTC)               += hp_sdc_rtc.o
+obj-$(CONFIG_INPUT_IXP4XX_BEEPER)      += ixp4xx-beeper.o
diff --git a/drivers/input/misc/ixp4xx-beeper.c b/drivers/input/misc/ixp4xx-beeper.c
new file mode 100644 (file)
index 0000000..d448bb5
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+ * Generic IXP4xx beeper driver
+ *
+ * Copyright (C) 2005 Tower Technologies
+ *
+ * based on nslu2-io.c
+ *  Copyright (C) 2004 Karen Spearel
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("ixp4xx beeper driver");
+MODULE_LICENSE("GPL");
+
+static DEFINE_SPINLOCK(beep_lock);
+
+static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&beep_lock, flags);
+
+        if (count) {
+               gpio_line_config(pin, IXP4XX_GPIO_OUT);
+               gpio_line_set(pin, IXP4XX_GPIO_LOW);
+
+               *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
+       } else {
+               gpio_line_config(pin, IXP4XX_GPIO_IN);
+               gpio_line_set(pin, IXP4XX_GPIO_HIGH);
+
+               *IXP4XX_OSRT2 = 0;
+       }
+
+       spin_unlock_irqrestore(&beep_lock, flags);
+}
+
+static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+       unsigned int pin = (unsigned int) dev->private;
+       unsigned int count = 0;
+
+       if (type != EV_SND)
+               return -1;
+
+       switch (code) {
+               case SND_BELL:
+                       if (value)
+                               value = 1000;
+               case SND_TONE:
+                       break;
+               default:
+                       return -1;
+       }
+
+       if (value > 20 && value < 32767)
+#ifndef FREQ
+               count = (ixp4xx_get_board_tick_rate() / (value * 4)) - 1;
+#else
+               count = (FREQ / (value * 4)) - 1;
+#endif
+
+       ixp4xx_spkr_control(pin, count);
+
+       return 0;
+}
+
+static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+       /* clear interrupt */
+       *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
+
+       /* flip the beeper output */
+       *IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id);
+
+       return IRQ_HANDLED;
+}
+
+static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)
+{
+       struct input_dev *input_dev;
+       int err;
+
+       input_dev = input_allocate_device();
+       if (!input_dev)
+               return -ENOMEM;
+
+       input_dev->private = (void *) dev->id;
+       input_dev->name = "ixp4xx beeper",
+       input_dev->phys = "ixp4xx/gpio";
+       input_dev->id.bustype = BUS_HOST;
+       input_dev->id.vendor  = 0x001f;
+       input_dev->id.product = 0x0001;
+       input_dev->id.version = 0x0100;
+       input_dev->cdev.dev = &dev->dev;
+
+       input_dev->evbit[0] = BIT(EV_SND);
+       input_dev->sndbit[0] = BIT(SND_BELL) | BIT(SND_TONE);
+       input_dev->event = ixp4xx_spkr_event;
+
+       err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
+                         SA_INTERRUPT | SA_TIMER, "ixp4xx-beeper", (void *) dev->id);
+       if (err)
+               goto err_free_device;
+
+       err = input_register_device(input_dev);
+       if (err)
+               goto err_free_irq;
+
+       platform_set_drvdata(dev, input_dev);
+
+       return 0;
+
+ err_free_irq:
+       free_irq(IRQ_IXP4XX_TIMER2, dev);
+ err_free_device:
+       input_free_device(input_dev);
+
+       return err;
+}
+
+static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)
+{
+       struct input_dev *input_dev = platform_get_drvdata(dev);
+       unsigned int pin = (unsigned int) input_dev->private;
+
+       input_unregister_device(input_dev);
+       platform_set_drvdata(dev, NULL);
+
+       /* turn the speaker off */
+       disable_irq(IRQ_IXP4XX_TIMER2);
+       ixp4xx_spkr_control(pin, 0);
+
+       free_irq(IRQ_IXP4XX_TIMER2, dev);
+
+       return 0;
+}
+
+static void ixp4xx_spkr_shutdown(struct platform_device *dev)
+{
+       struct input_dev *input_dev = platform_get_drvdata(dev);
+       unsigned int pin = (unsigned int) input_dev->private;
+
+       /* turn off the speaker */
+       disable_irq(IRQ_IXP4XX_TIMER2);
+       ixp4xx_spkr_control(pin, 0);
+}
+
+static struct platform_driver ixp4xx_spkr_platform_driver = {
+       .driver         = {
+               .name   = "ixp4xx-beeper",
+               .owner  = THIS_MODULE,
+       },
+       .probe          = ixp4xx_spkr_probe,
+       .remove         = __devexit_p(ixp4xx_spkr_remove),
+       .shutdown       = ixp4xx_spkr_shutdown,
+};
+
+static int __init ixp4xx_spkr_init(void)
+{
+       return platform_driver_register(&ixp4xx_spkr_platform_driver);
+}
+
+static void __exit ixp4xx_spkr_exit(void)
+{
+       platform_driver_unregister(&ixp4xx_spkr_platform_driver);
+}
+
+module_init(ixp4xx_spkr_init);
+module_exit(ixp4xx_spkr_exit);