2005-04-17 02:20:36 +04:00
/*
* Driver for PC - speaker like devices found on various Sparc systems .
*
* Copyright ( c ) 2002 Vojtech Pavlik
2006-06-23 12:44:10 +04:00
* Copyright ( c ) 2002 , 2006 David S . Miller ( davem @ davemloft . net )
2005-04-17 02:20:36 +04:00
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/init.h>
# include <linux/input.h>
2005-12-21 08:52:35 +03:00
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
# include <asm/io.h>
# include <asm/ebus.h>
# include <asm/isa.h>
2006-06-23 12:44:10 +04:00
MODULE_AUTHOR ( " David S. Miller <davem@davemloft.net> " ) ;
2005-09-15 11:01:51 +04:00
MODULE_DESCRIPTION ( " Sparc Speaker beeper driver " ) ;
2005-04-17 02:20:36 +04:00
MODULE_LICENSE ( " GPL " ) ;
2006-06-23 12:44:10 +04:00
struct sparcspkr_state {
const char * name ;
unsigned long iobase ;
int ( * event ) ( struct input_dev * dev , unsigned int type , unsigned int code , int value ) ;
spinlock_t lock ;
struct input_dev * input_dev ;
} ;
2005-04-17 02:20:36 +04:00
static int ebus_spkr_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
2007-04-12 09:35:32 +04:00
struct sparcspkr_state * state = dev_get_drvdata ( dev - > dev . parent ) ;
2005-04-17 02:20:36 +04:00
unsigned int count = 0 ;
unsigned long flags ;
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 )
count = 1193182 / value ;
2006-06-23 12:44:10 +04:00
spin_lock_irqsave ( & state - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
/* EBUS speaker only has on/off state, the frequency does not
* appear to be programmable .
*/
2006-06-23 12:44:10 +04:00
if ( state - > iobase & 0x2UL )
outb ( ! ! count , state - > iobase ) ;
2005-12-21 08:52:35 +03:00
else
2006-06-23 12:44:10 +04:00
outl ( ! ! count , state - > iobase ) ;
2005-04-17 02:20:36 +04:00
2006-06-23 12:44:10 +04:00
spin_unlock_irqrestore ( & state - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
static int isa_spkr_event ( struct input_dev * dev , unsigned int type , unsigned int code , int value )
{
2007-04-12 09:35:32 +04:00
struct sparcspkr_state * state = dev_get_drvdata ( dev - > dev . parent ) ;
2005-04-17 02:20:36 +04:00
unsigned int count = 0 ;
unsigned long flags ;
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 )
count = 1193182 / value ;
2006-06-23 12:44:10 +04:00
spin_lock_irqsave ( & state - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
if ( count ) {
/* enable counter 2 */
2006-06-23 12:44:10 +04:00
outb ( inb ( state - > iobase + 0x61 ) | 3 , state - > iobase + 0x61 ) ;
2005-04-17 02:20:36 +04:00
/* set command for counter 2, 2 byte write */
2006-06-23 12:44:10 +04:00
outb ( 0xB6 , state - > iobase + 0x43 ) ;
2005-04-17 02:20:36 +04:00
/* select desired HZ */
2006-06-23 12:44:10 +04:00
outb ( count & 0xff , state - > iobase + 0x42 ) ;
outb ( ( count > > 8 ) & 0xff , state - > iobase + 0x42 ) ;
2005-04-17 02:20:36 +04:00
} else {
/* disable counter 2 */
2006-06-23 12:44:10 +04:00
outb ( inb_p ( state - > iobase + 0x61 ) & 0xFC , state - > iobase + 0x61 ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-23 12:44:10 +04:00
spin_unlock_irqrestore ( & state - > lock , flags ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2006-06-23 12:44:10 +04:00
static int __devinit sparcspkr_probe ( struct device * dev )
2005-04-17 02:20:36 +04:00
{
2006-06-23 12:44:10 +04:00
struct sparcspkr_state * state = dev_get_drvdata ( dev ) ;
2005-12-21 08:52:35 +03:00
struct input_dev * input_dev ;
int error ;
2005-04-17 02:20:36 +04:00
2005-12-21 08:52:35 +03:00
input_dev = input_allocate_device ( ) ;
if ( ! input_dev )
2005-09-15 11:01:51 +04:00
return - ENOMEM ;
2006-06-23 12:44:10 +04:00
input_dev - > name = state - > name ;
2005-12-21 08:52:35 +03:00
input_dev - > phys = " sparc/input0 " ;
input_dev - > id . bustype = BUS_ISA ;
input_dev - > id . vendor = 0x001f ;
input_dev - > id . product = 0x0001 ;
input_dev - > id . version = 0x0100 ;
2007-04-12 09:35:32 +04:00
input_dev - > dev . parent = dev ;
2005-04-17 02:20:36 +04:00
2005-12-21 08:52:35 +03:00
input_dev - > evbit [ 0 ] = BIT ( EV_SND ) ;
input_dev - > sndbit [ 0 ] = BIT ( SND_BELL ) | BIT ( SND_TONE ) ;
2005-04-17 02:20:36 +04:00
2006-06-23 12:44:10 +04:00
input_dev - > event = state - > event ;
2005-12-21 08:52:35 +03:00
error = input_register_device ( input_dev ) ;
if ( error ) {
input_free_device ( input_dev ) ;
return error ;
}
2006-06-23 12:44:10 +04:00
state - > input_dev = input_dev ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
static int __devexit sparcspkr_remove ( struct of_device * dev )
2005-12-21 08:52:35 +03:00
{
2006-06-23 12:44:10 +04:00
struct sparcspkr_state * state = dev_get_drvdata ( & dev - > dev ) ;
struct input_dev * input_dev = state - > input_dev ;
2005-12-21 08:52:35 +03:00
/* turn off the speaker */
2006-06-23 12:44:10 +04:00
state - > event ( input_dev , EV_SND , SND_BELL , 0 ) ;
input_unregister_device ( input_dev ) ;
dev_set_drvdata ( & dev - > dev , NULL ) ;
kfree ( state ) ;
2005-12-21 08:52:35 +03:00
return 0 ;
}
2006-06-23 12:44:10 +04:00
static int sparcspkr_shutdown ( struct of_device * dev )
2005-12-21 08:52:35 +03:00
{
2006-06-23 12:44:10 +04:00
struct sparcspkr_state * state = dev_get_drvdata ( & dev - > dev ) ;
struct input_dev * input_dev = state - > input_dev ;
2005-12-21 08:52:35 +03:00
/* turn off the speaker */
2006-06-23 12:44:10 +04:00
state - > event ( input_dev , EV_SND , SND_BELL , 0 ) ;
return 0 ;
}
static int __devinit ebus_beep_probe ( struct of_device * dev , const struct of_device_id * match )
{
struct linux_ebus_device * edev = to_ebus_device ( & dev - > dev ) ;
struct sparcspkr_state * state ;
int err ;
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return - ENOMEM ;
state - > name = " Sparc EBUS Speaker " ;
state - > iobase = edev - > resource [ 0 ] . start ;
state - > event = ebus_spkr_event ;
spin_lock_init ( & state - > lock ) ;
dev_set_drvdata ( & dev - > dev , state ) ;
err = sparcspkr_probe ( & dev - > dev ) ;
if ( err ) {
dev_set_drvdata ( & dev - > dev , NULL ) ;
kfree ( state ) ;
}
return 0 ;
2005-12-21 08:52:35 +03:00
}
2006-06-23 12:44:10 +04:00
static struct of_device_id ebus_beep_match [ ] = {
{
. name = " beep " ,
2005-12-21 08:52:35 +03:00
} ,
2006-06-23 12:44:10 +04:00
{ } ,
2005-12-21 08:52:35 +03:00
} ;
2006-06-23 12:44:10 +04:00
static struct of_platform_driver ebus_beep_driver = {
. name = " beep " ,
. match_table = ebus_beep_match ,
. probe = ebus_beep_probe ,
. remove = sparcspkr_remove ,
. shutdown = sparcspkr_shutdown ,
} ;
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
static int __devinit isa_beep_probe ( struct of_device * dev , const struct of_device_id * match )
2005-12-21 08:52:35 +03:00
{
2006-06-23 12:44:10 +04:00
struct sparc_isa_device * idev = to_isa_device ( & dev - > dev ) ;
struct sparcspkr_state * state ;
int err ;
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
state = kzalloc ( sizeof ( * state ) , GFP_KERNEL ) ;
if ( ! state )
return - ENOMEM ;
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
state - > name = " Sparc ISA Speaker " ;
state - > iobase = idev - > resource . start ;
state - > event = isa_spkr_event ;
spin_lock_init ( & state - > lock ) ;
dev_set_drvdata ( & dev - > dev , state ) ;
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
err = sparcspkr_probe ( & dev - > dev ) ;
if ( err ) {
dev_set_drvdata ( & dev - > dev , NULL ) ;
kfree ( state ) ;
}
2005-12-21 08:52:35 +03:00
return 0 ;
2006-06-23 12:44:10 +04:00
}
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
static struct of_device_id isa_beep_match [ ] = {
{
. name = " dma " ,
} ,
{ } ,
} ;
2005-12-21 08:52:35 +03:00
2006-06-23 12:44:10 +04:00
static struct of_platform_driver isa_beep_driver = {
. name = " beep " ,
. match_table = isa_beep_match ,
. probe = isa_beep_probe ,
. remove = sparcspkr_remove ,
. shutdown = sparcspkr_shutdown ,
} ;
2005-04-17 02:20:36 +04:00
static int __init sparcspkr_init ( void )
{
2006-06-23 12:44:10 +04:00
int err = of_register_driver ( & ebus_beep_driver , & ebus_bus_type ) ;
if ( ! err ) {
err = of_register_driver ( & isa_beep_driver , & isa_bus_type ) ;
if ( err )
of_unregister_driver ( & ebus_beep_driver ) ;
2005-04-17 02:20:36 +04:00
}
2006-06-23 12:44:10 +04:00
return err ;
2005-04-17 02:20:36 +04:00
}
static void __exit sparcspkr_exit ( void )
{
2006-06-23 12:44:10 +04:00
of_unregister_driver ( & ebus_beep_driver ) ;
of_unregister_driver ( & isa_beep_driver ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( sparcspkr_init ) ;
module_exit ( sparcspkr_exit ) ;