2006-01-29 21:50:40 -05:00
/*
* 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>
2006-02-15 00:48:40 -05:00
# include <linux/interrupt.h>
2006-01-29 21:50:40 -05:00
# 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 ) ;