linux/drivers/input/misc/ixp4xx-beeper.c
<<
>>
Prefs
   1/*
   2 * Generic IXP4xx beeper driver
   3 *
   4 * Copyright (C) 2005 Tower Technologies
   5 *
   6 * based on nslu2-io.c
   7 *  Copyright (C) 2004 Karen Spearel
   8 *
   9 * Author: Alessandro Zummo <a.zummo@towertech.it>
  10 * Maintainers: http://www.nslu2-linux.org/
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 *
  16 */
  17
  18#include <linux/module.h>
  19#include <linux/input.h>
  20#include <linux/delay.h>
  21#include <linux/platform_device.h>
  22#include <linux/interrupt.h>
  23#include <linux/gpio.h>
  24#include <mach/hardware.h>
  25
  26MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
  27MODULE_DESCRIPTION("ixp4xx beeper driver");
  28MODULE_LICENSE("GPL");
  29MODULE_ALIAS("platform:ixp4xx-beeper");
  30
  31static DEFINE_SPINLOCK(beep_lock);
  32
  33static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)
  34{
  35        unsigned long flags;
  36
  37        spin_lock_irqsave(&beep_lock, flags);
  38
  39        if (count) {
  40                gpio_direction_output(pin, 0);
  41                *IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
  42        } else {
  43                gpio_direction_output(pin, 1);
  44                gpio_direction_input(pin);
  45                *IXP4XX_OSRT2 = 0;
  46        }
  47
  48        spin_unlock_irqrestore(&beep_lock, flags);
  49}
  50
  51static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
  52{
  53        unsigned int pin = (unsigned int) input_get_drvdata(dev);
  54        unsigned int count = 0;
  55
  56        if (type != EV_SND)
  57                return -1;
  58
  59        switch (code) {
  60                case SND_BELL:
  61                        if (value)
  62                                value = 1000;
  63                case SND_TONE:
  64                        break;
  65                default:
  66                        return -1;
  67        }
  68
  69        if (value > 20 && value < 32767)
  70                count = (ixp4xx_timer_freq / (value * 4)) - 1;
  71
  72        ixp4xx_spkr_control(pin, count);
  73
  74        return 0;
  75}
  76
  77static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)
  78{
  79        unsigned int pin = (unsigned int) dev_id;
  80
  81        /* clear interrupt */
  82        *IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;
  83
  84        /* flip the beeper output */
  85        gpio_set_value(pin, !gpio_get_value(pin));
  86
  87        return IRQ_HANDLED;
  88}
  89
  90static int ixp4xx_spkr_probe(struct platform_device *dev)
  91{
  92        struct input_dev *input_dev;
  93        int err;
  94
  95        input_dev = input_allocate_device();
  96        if (!input_dev)
  97                return -ENOMEM;
  98
  99        input_set_drvdata(input_dev, (void *) dev->id);
 100
 101        input_dev->name = "ixp4xx beeper",
 102        input_dev->phys = "ixp4xx/gpio";
 103        input_dev->id.bustype = BUS_HOST;
 104        input_dev->id.vendor  = 0x001f;
 105        input_dev->id.product = 0x0001;
 106        input_dev->id.version = 0x0100;
 107        input_dev->dev.parent = &dev->dev;
 108
 109        input_dev->evbit[0] = BIT_MASK(EV_SND);
 110        input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
 111        input_dev->event = ixp4xx_spkr_event;
 112
 113        err = gpio_request(dev->id, "ixp4-beeper");
 114        if (err)
 115                goto err_free_device;
 116
 117        err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,
 118                          IRQF_NO_SUSPEND, "ixp4xx-beeper",
 119                          (void *) dev->id);
 120        if (err)
 121                goto err_free_gpio;
 122
 123        err = input_register_device(input_dev);
 124        if (err)
 125                goto err_free_irq;
 126
 127        platform_set_drvdata(dev, input_dev);
 128
 129        return 0;
 130
 131 err_free_irq:
 132        free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
 133 err_free_gpio:
 134        gpio_free(dev->id);
 135 err_free_device:
 136        input_free_device(input_dev);
 137
 138        return err;
 139}
 140
 141static int ixp4xx_spkr_remove(struct platform_device *dev)
 142{
 143        struct input_dev *input_dev = platform_get_drvdata(dev);
 144        unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
 145
 146        input_unregister_device(input_dev);
 147
 148        /* turn the speaker off */
 149        disable_irq(IRQ_IXP4XX_TIMER2);
 150        ixp4xx_spkr_control(pin, 0);
 151
 152        free_irq(IRQ_IXP4XX_TIMER2, (void *)dev->id);
 153        gpio_free(dev->id);
 154
 155        return 0;
 156}
 157
 158static void ixp4xx_spkr_shutdown(struct platform_device *dev)
 159{
 160        struct input_dev *input_dev = platform_get_drvdata(dev);
 161        unsigned int pin = (unsigned int) input_get_drvdata(input_dev);
 162
 163        /* turn off the speaker */
 164        disable_irq(IRQ_IXP4XX_TIMER2);
 165        ixp4xx_spkr_control(pin, 0);
 166}
 167
 168static struct platform_driver ixp4xx_spkr_platform_driver = {
 169        .driver         = {
 170                .name   = "ixp4xx-beeper",
 171        },
 172        .probe          = ixp4xx_spkr_probe,
 173        .remove         = ixp4xx_spkr_remove,
 174        .shutdown       = ixp4xx_spkr_shutdown,
 175};
 176module_platform_driver(ixp4xx_spkr_platform_driver);
 177
 178