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