Path: blob/master/drivers/input/misc/ixp4xx-beeper.c
15111 views
/*1* Generic IXP4xx beeper driver2*3* Copyright (C) 2005 Tower Technologies4*5* based on nslu2-io.c6* Copyright (C) 2004 Karen Spearel7*8* Author: Alessandro Zummo <[email protected]>9* Maintainers: http://www.nslu2-linux.org/10*11* This program is free software; you can redistribute it and/or modify12* it under the terms of the GNU General Public License version 2 as13* published by the Free Software Foundation.14*15*/1617#include <linux/module.h>18#include <linux/input.h>19#include <linux/delay.h>20#include <linux/platform_device.h>21#include <linux/interrupt.h>22#include <mach/hardware.h>2324MODULE_AUTHOR("Alessandro Zummo <[email protected]>");25MODULE_DESCRIPTION("ixp4xx beeper driver");26MODULE_LICENSE("GPL");27MODULE_ALIAS("platform:ixp4xx-beeper");2829static DEFINE_SPINLOCK(beep_lock);3031static void ixp4xx_spkr_control(unsigned int pin, unsigned int count)32{33unsigned long flags;3435spin_lock_irqsave(&beep_lock, flags);3637if (count) {38gpio_line_config(pin, IXP4XX_GPIO_OUT);39gpio_line_set(pin, IXP4XX_GPIO_LOW);4041*IXP4XX_OSRT2 = (count & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;42} else {43gpio_line_config(pin, IXP4XX_GPIO_IN);44gpio_line_set(pin, IXP4XX_GPIO_HIGH);4546*IXP4XX_OSRT2 = 0;47}4849spin_unlock_irqrestore(&beep_lock, flags);50}5152static int ixp4xx_spkr_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)53{54unsigned int pin = (unsigned int) input_get_drvdata(dev);55unsigned int count = 0;5657if (type != EV_SND)58return -1;5960switch (code) {61case SND_BELL:62if (value)63value = 1000;64case SND_TONE:65break;66default:67return -1;68}6970if (value > 20 && value < 32767)71count = (IXP4XX_TIMER_FREQ / (value * 4)) - 1;7273ixp4xx_spkr_control(pin, count);7475return 0;76}7778static irqreturn_t ixp4xx_spkr_interrupt(int irq, void *dev_id)79{80/* clear interrupt */81*IXP4XX_OSST = IXP4XX_OSST_TIMER_2_PEND;8283/* flip the beeper output */84*IXP4XX_GPIO_GPOUTR ^= (1 << (unsigned int) dev_id);8586return IRQ_HANDLED;87}8889static int __devinit ixp4xx_spkr_probe(struct platform_device *dev)90{91struct input_dev *input_dev;92int err;9394input_dev = input_allocate_device();95if (!input_dev)96return -ENOMEM;9798input_set_drvdata(input_dev, (void *) dev->id);99100input_dev->name = "ixp4xx beeper",101input_dev->phys = "ixp4xx/gpio";102input_dev->id.bustype = BUS_HOST;103input_dev->id.vendor = 0x001f;104input_dev->id.product = 0x0001;105input_dev->id.version = 0x0100;106input_dev->dev.parent = &dev->dev;107108input_dev->evbit[0] = BIT_MASK(EV_SND);109input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);110input_dev->event = ixp4xx_spkr_event;111112err = request_irq(IRQ_IXP4XX_TIMER2, &ixp4xx_spkr_interrupt,113IRQF_DISABLED | IRQF_NO_SUSPEND, "ixp4xx-beeper",114(void *) dev->id);115if (err)116goto err_free_device;117118err = input_register_device(input_dev);119if (err)120goto err_free_irq;121122platform_set_drvdata(dev, input_dev);123124return 0;125126err_free_irq:127free_irq(IRQ_IXP4XX_TIMER2, dev);128err_free_device:129input_free_device(input_dev);130131return err;132}133134static int __devexit ixp4xx_spkr_remove(struct platform_device *dev)135{136struct input_dev *input_dev = platform_get_drvdata(dev);137unsigned int pin = (unsigned int) input_get_drvdata(input_dev);138139input_unregister_device(input_dev);140platform_set_drvdata(dev, NULL);141142/* turn the speaker off */143disable_irq(IRQ_IXP4XX_TIMER2);144ixp4xx_spkr_control(pin, 0);145146free_irq(IRQ_IXP4XX_TIMER2, dev);147148return 0;149}150151static void ixp4xx_spkr_shutdown(struct platform_device *dev)152{153struct input_dev *input_dev = platform_get_drvdata(dev);154unsigned int pin = (unsigned int) input_get_drvdata(input_dev);155156/* turn off the speaker */157disable_irq(IRQ_IXP4XX_TIMER2);158ixp4xx_spkr_control(pin, 0);159}160161static struct platform_driver ixp4xx_spkr_platform_driver = {162.driver = {163.name = "ixp4xx-beeper",164.owner = THIS_MODULE,165},166.probe = ixp4xx_spkr_probe,167.remove = __devexit_p(ixp4xx_spkr_remove),168.shutdown = ixp4xx_spkr_shutdown,169};170171static int __init ixp4xx_spkr_init(void)172{173return platform_driver_register(&ixp4xx_spkr_platform_driver);174}175176static void __exit ixp4xx_spkr_exit(void)177{178platform_driver_unregister(&ixp4xx_spkr_platform_driver);179}180181module_init(ixp4xx_spkr_init);182module_exit(ixp4xx_spkr_exit);183184185