2005-04-17 02:20:36 +04:00
/* Terratec ActiveRadio ISA Standalone card driver for Linux radio support
* ( c ) 1999 R . Offermanns ( rolf @ offermanns . de )
* based on the aimslab radio driver from M . Kirkwood
* many thanks to Michael Becker and Friedhelm Birth ( from TerraTec )
2006-04-08 23:06:16 +04:00
*
2005-04-17 02:20:36 +04:00
*
* History :
* 1999 - 05 - 21 First preview release
2006-04-08 23:06:16 +04:00
*
2005-04-17 02:20:36 +04:00
* Notes on the hardware :
* There are two " main " chips on the card :
* - Philips OM5610 ( http : //www-us.semiconductors.philips.com/acrobat/datasheets/OM5610_2.pdf)
* - Philips SAA6588 ( http : //www-us.semiconductors.philips.com/acrobat/datasheets/SAA6588_1.pdf)
* ( you can get the datasheet at the above links )
*
* Frequency control is done digitally - - ie out ( port , encodefreq ( 95.8 ) ) ;
* Volume Control is done digitally
*
2012-01-16 12:15:09 +04:00
* Converted to the radio - isa framework by Hans Verkuil < hans . verkuil @ cisco . com >
MAINTAINERS & files: Canonize the e-mails I use at files
From now on, I'll start using my @kernel.org as my development e-mail.
As such, let's remove the entries that point to the old
mchehab@s-opensource.com at MAINTAINERS file.
For the files written with a copyright with mchehab@s-opensource,
let's keep Samsung on their names, using mchehab+samsung@kernel.org,
in order to keep pointing to my employer, with sponsors the work.
For the files written before I join Samsung (on July, 4 2013),
let's just use mchehab@kernel.org.
For bug reports, we can simply point to just kernel.org, as
this will reach my mchehab+samsung inbox anyway.
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Brian Warner <brian.warner@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
2018-04-25 12:34:48 +03:00
* Converted to V4L2 API by Mauro Carvalho Chehab < mchehab @ kernel . org >
2005-04-17 02:20:36 +04:00
*/
2018-01-04 21:08:56 +03:00
# include <linux/module.h> /* Modules */
2005-04-17 02:20:36 +04:00
# include <linux/init.h> /* Initdata */
2005-09-13 12:25:15 +04:00
# include <linux/ioport.h> /* request_region */
2006-08-08 16:10:03 +04:00
# include <linux/videodev2.h> /* kernel radio structs */
2009-03-06 19:53:58 +03:00
# include <linux/mutex.h>
# include <linux/io.h> /* outb, outb_p */
2012-02-29 12:50:27 +04:00
# include <linux/slab.h>
2009-03-06 19:53:58 +03:00
# include <media/v4l2-device.h>
2008-07-20 15:12:02 +04:00
# include <media/v4l2-ioctl.h>
2012-01-16 12:15:09 +04:00
# include "radio-isa.h"
2005-04-17 02:20:36 +04:00
2012-01-16 12:15:09 +04:00
MODULE_AUTHOR ( " R. Offermans & others " ) ;
2009-03-06 19:53:58 +03:00
MODULE_DESCRIPTION ( " A driver for the TerraTec ActiveRadio Standalone radio card. " ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-01-16 12:15:09 +04:00
MODULE_VERSION ( " 0.1.99 " ) ;
2009-03-06 19:53:58 +03:00
2012-01-16 12:15:09 +04:00
/* Note: there seems to be only one possible port (0x590), but without
hardware this is hard to verify . For now , this is the only one we will
support . */
static int io = 0x590 ;
2009-03-06 19:53:58 +03:00
static int radio_nr = - 1 ;
2012-01-16 12:15:09 +04:00
module_param ( radio_nr , int , 0444 ) ;
MODULE_PARM_DESC ( radio_nr , " Radio device number " ) ;
2006-08-08 16:10:03 +04:00
2018-01-04 21:08:56 +03:00
# define WRT_DIS 0x00
2005-04-17 02:20:36 +04:00
# define CLK_OFF 0x00
# define IIC_DATA 0x01
# define IIC_CLK 0x02
# define DATA 0x04
2018-01-04 21:08:56 +03:00
# define CLK_ON 0x08
2005-04-17 02:20:36 +04:00
# define WRT_EN 0x10
2012-01-16 12:15:09 +04:00
static struct radio_isa_card * terratec_alloc ( void )
2005-04-17 02:20:36 +04:00
{
2012-01-16 12:15:09 +04:00
return kzalloc ( sizeof ( struct radio_isa_card ) , GFP_KERNEL ) ;
}
2005-04-17 02:20:36 +04:00
2012-01-16 12:15:09 +04:00
static int terratec_s_mute_volume ( struct radio_isa_card * isa , bool mute , int vol )
2005-04-17 02:20:36 +04:00
{
int i ;
2009-03-06 19:53:58 +03:00
2012-01-16 12:15:09 +04:00
if ( mute )
vol = 0 ;
vol = vol + ( vol * 32 ) ; /* change both channels */
2009-03-06 19:53:58 +03:00
for ( i = 0 ; i < 8 ; i + + ) {
2012-01-16 12:15:09 +04:00
if ( vol & ( 0x80 > > i ) )
outb ( 0x80 , isa - > io + 1 ) ;
2009-03-06 19:53:58 +03:00
else
2012-01-16 12:15:09 +04:00
outb ( 0x00 , isa - > io + 1 ) ;
2005-04-17 02:20:36 +04:00
}
return 0 ;
}
/* this is the worst part in this driver */
/* many more or less strange things are going on here, but hey, it works :) */
2012-01-16 12:15:09 +04:00
static int terratec_s_frequency ( struct radio_isa_card * isa , u32 freq )
2006-04-08 23:06:16 +04:00
{
2005-04-17 02:20:36 +04:00
int i ;
int p ;
2012-01-16 12:15:09 +04:00
int temp ;
2005-04-17 02:20:36 +04:00
long rest ;
unsigned char buffer [ 25 ] ; /* we have to bit shift 25 registers */
2012-01-16 12:15:09 +04:00
freq = freq / 160 ; /* convert the freq. to a nice to handle value */
2009-03-06 19:53:58 +03:00
memset ( buffer , 0 , sizeof ( buffer ) ) ;
rest = freq * 10 + 10700 ; /* I once had understood what is going on here */
2005-04-17 02:20:36 +04:00
/* maybe some wise guy (friedhelm?) can comment this stuff */
2009-03-06 19:53:58 +03:00
i = 13 ;
p = 10 ;
temp = 102400 ;
while ( rest ! = 0 ) {
if ( rest % temp = = rest )
2005-04-17 02:20:36 +04:00
buffer [ i ] = 0 ;
2009-03-06 19:53:58 +03:00
else {
2006-04-08 23:06:16 +04:00
buffer [ i ] = 1 ;
2009-03-06 19:53:58 +03:00
rest = rest - temp ;
2005-04-17 02:20:36 +04:00
}
i - - ;
p - - ;
2009-03-06 19:53:58 +03:00
temp = temp / 2 ;
2007-08-28 01:16:54 +04:00
}
2005-04-17 02:20:36 +04:00
2009-03-06 19:53:58 +03:00
for ( i = 24 ; i > - 1 ; i - - ) { /* bit shift the values to the radiocard */
if ( buffer [ i ] = = 1 ) {
2012-01-16 12:15:09 +04:00
outb ( WRT_EN | DATA , isa - > io ) ;
outb ( WRT_EN | DATA | CLK_ON , isa - > io ) ;
outb ( WRT_EN | DATA , isa - > io ) ;
2009-03-06 19:53:58 +03:00
} else {
2012-01-16 12:15:09 +04:00
outb ( WRT_EN | 0x00 , isa - > io ) ;
outb ( WRT_EN | 0x00 | CLK_ON , isa - > io ) ;
2005-04-17 02:20:36 +04:00
}
2007-04-23 06:15:47 +04:00
}
2012-01-16 12:15:09 +04:00
outb ( 0x00 , isa - > io ) ;
2007-04-23 06:15:47 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2012-01-16 12:15:09 +04:00
static u32 terratec_g_signal ( struct radio_isa_card * isa )
2009-03-06 19:53:58 +03:00
{
2012-01-16 12:15:09 +04:00
/* bit set = no signal present */
return ( inb ( isa - > io ) & 2 ) ? 0 : 0xffff ;
2009-03-06 19:53:58 +03:00
}
2005-04-17 02:20:36 +04:00
2012-01-16 12:15:09 +04:00
static const struct radio_isa_ops terratec_ops = {
. alloc = terratec_alloc ,
. s_mute_volume = terratec_s_mute_volume ,
. s_frequency = terratec_s_frequency ,
. g_signal = terratec_g_signal ,
2005-04-17 02:20:36 +04:00
} ;
2012-01-16 12:15:09 +04:00
static const int terratec_ioports [ ] = { 0x590 } ;
static struct radio_isa_driver terratec_driver = {
. driver = {
. match = radio_isa_match ,
. probe = radio_isa_probe ,
. remove = radio_isa_remove ,
. driver = {
. name = " radio-terratec " ,
} ,
} ,
. io_params = & io ,
. radio_nr_params = & radio_nr ,
. io_ports = terratec_ioports ,
. num_of_io_ports = ARRAY_SIZE ( terratec_ioports ) ,
. region_size = 2 ,
. card = " TerraTec ActiveRadio " ,
. ops = & terratec_ops ,
. has_stereo = true ,
. max_volume = 10 ,
2005-04-17 02:20:36 +04:00
} ;
static int __init terratec_init ( void )
{
2012-01-16 12:15:09 +04:00
return isa_register_driver ( & terratec_driver . driver , 1 ) ;
2005-04-17 02:20:36 +04:00
}
2009-03-06 19:53:58 +03:00
static void __exit terratec_exit ( void )
2005-04-17 02:20:36 +04:00
{
2012-01-16 12:15:09 +04:00
isa_unregister_driver ( & terratec_driver . driver ) ;
2005-04-17 02:20:36 +04:00
}
module_init ( terratec_init ) ;
2009-03-06 19:53:58 +03:00
module_exit ( terratec_exit ) ;
2005-04-17 02:20:36 +04:00