2008-04-19 04:34:00 +04:00
/*
* Driver for the Auvitek USB bridge
*
2008-09-04 00:12:12 +04:00
* Copyright ( c ) 2008 Steven Toth < stoth @ linuxtv . org >
2008-04-19 04:34:00 +04:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
*
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "au0828.h"
# include "au0828-cards.h"
2009-03-11 09:00:40 +03:00
# include "au8522.h"
2009-03-11 09:00:47 +03:00
# include "media/tuner.h"
# include "media/v4l2-common.h"
2009-03-11 09:00:40 +03:00
void hvr950q_cs5340_audio ( void * priv , int enable )
{
/* Because the HVR-950q shares an i2s bus between the cs5340 and the
au8522 , we need to hold cs5340 in reset when using the au8522 */
struct au0828_dev * dev = priv ;
if ( enable = = 1 )
au0828_set ( dev , REG_000 , 0x10 ) ;
else
au0828_clear ( dev , REG_000 , 0x10 ) ;
}
2008-04-19 04:34:00 +04:00
struct au0828_board au0828_boards [ ] = {
[ AU0828_BOARD_UNKNOWN ] = {
. name = " Unknown board " ,
2009-03-11 09:00:47 +03:00
. tuner_type = UNSET ,
. tuner_addr = ADDR_UNSET ,
2008-04-19 04:34:00 +04:00
} ,
[ AU0828_BOARD_HAUPPAUGE_HVR850 ] = {
. name = " Hauppauge HVR850 " ,
2009-03-11 09:00:47 +03:00
. tuner_type = TUNER_XC5000 ,
. tuner_addr = 0x61 ,
2009-04-01 07:11:31 +04:00
. i2c_clk_divider = AU0828_I2C_CLK_30KHZ ,
2009-03-11 09:00:43 +03:00
. input = {
{
. type = AU0828_VMUX_TELEVISION ,
. vmux = AU8522_COMPOSITE_CH4_SIF ,
. amux = AU8522_AUDIO_SIF ,
} ,
{
. type = AU0828_VMUX_COMPOSITE ,
. vmux = AU8522_COMPOSITE_CH1 ,
. amux = AU8522_AUDIO_NONE ,
. audio_setup = hvr950q_cs5340_audio ,
} ,
{
. type = AU0828_VMUX_SVIDEO ,
. vmux = AU8522_SVIDEO_CH13 ,
. amux = AU8522_AUDIO_NONE ,
. audio_setup = hvr950q_cs5340_audio ,
} ,
} ,
2008-04-19 04:34:00 +04:00
} ,
[ AU0828_BOARD_HAUPPAUGE_HVR950Q ] = {
. name = " Hauppauge HVR950Q " ,
2009-03-11 09:00:47 +03:00
. tuner_type = TUNER_XC5000 ,
. tuner_addr = 0x61 ,
2009-04-01 07:11:31 +04:00
/* The au0828 hardware i2c implementation does not properly
support the xc5000 ' s i2c clock stretching . So we need to
lower the clock frequency enough where the 15u s clock
stretch fits inside of a normal clock cycle , or else the
au0828 fails to set the STOP bit . A 30 KHz clock puts the
clock pulse width at 18u s */
. i2c_clk_divider = AU0828_I2C_CLK_30KHZ ,
2009-03-11 09:00:40 +03:00
. input = {
{
. type = AU0828_VMUX_TELEVISION ,
. vmux = AU8522_COMPOSITE_CH4_SIF ,
. amux = AU8522_AUDIO_SIF ,
} ,
{
. type = AU0828_VMUX_COMPOSITE ,
. vmux = AU8522_COMPOSITE_CH1 ,
. amux = AU8522_AUDIO_NONE ,
. audio_setup = hvr950q_cs5340_audio ,
} ,
{
. type = AU0828_VMUX_SVIDEO ,
. vmux = AU8522_SVIDEO_CH13 ,
. amux = AU8522_AUDIO_NONE ,
. audio_setup = hvr950q_cs5340_audio ,
} ,
} ,
2008-04-19 04:34:00 +04:00
} ,
2008-07-09 07:23:08 +04:00
[ AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL ] = {
. name = " Hauppauge HVR950Q rev xxF8 " ,
2009-03-11 09:00:47 +03:00
. tuner_type = UNSET ,
. tuner_addr = ADDR_UNSET ,
2009-04-01 07:11:31 +04:00
. i2c_clk_divider = AU0828_I2C_CLK_250KHZ ,
2008-07-09 07:23:08 +04:00
} ,
2008-04-19 04:34:00 +04:00
[ AU0828_BOARD_DVICO_FUSIONHDTV7 ] = {
. name = " DViCO FusionHDTV USB " ,
2009-03-11 09:00:47 +03:00
. tuner_type = UNSET ,
. tuner_addr = ADDR_UNSET ,
2009-04-01 07:11:31 +04:00
. i2c_clk_divider = AU0828_I2C_CLK_250KHZ ,
2008-04-19 04:34:00 +04:00
} ,
2008-09-03 23:46:36 +04:00
[ AU0828_BOARD_HAUPPAUGE_WOODBURY ] = {
. name = " Hauppauge Woodbury " ,
2009-03-11 09:00:47 +03:00
. tuner_type = UNSET ,
. tuner_addr = ADDR_UNSET ,
2009-04-01 07:11:31 +04:00
. i2c_clk_divider = AU0828_I2C_CLK_250KHZ ,
2008-09-03 23:46:36 +04:00
} ,
2008-04-19 04:34:00 +04:00
} ;
/* Tuner callback function for au0828 boards. Currently only needed
* for HVR1500Q , which has an xc5000 tuner .
*/
2008-09-12 20:31:45 +04:00
int au0828_tuner_callback ( void * priv , int component , int command , int arg )
2008-04-19 04:34:00 +04:00
{
struct au0828_dev * dev = priv ;
2008-04-19 04:42:30 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2008-04-19 04:39:11 +04:00
2009-03-11 09:00:47 +03:00
switch ( dev - > boardnr ) {
2008-04-19 04:34:00 +04:00
case AU0828_BOARD_HAUPPAUGE_HVR850 :
case AU0828_BOARD_HAUPPAUGE_HVR950Q :
2008-07-09 07:23:08 +04:00
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL :
2008-04-19 04:34:00 +04:00
case AU0828_BOARD_DVICO_FUSIONHDTV7 :
2008-04-18 04:41:28 +04:00
if ( command = = 0 ) {
2008-04-19 04:34:00 +04:00
/* Tuner Reset Command from xc5000 */
/* Drive the tuner into reset and out */
au0828_clear ( dev , REG_001 , 2 ) ;
2009-04-03 05:14:51 +04:00
mdelay ( 10 ) ;
2008-04-19 04:34:00 +04:00
au0828_set ( dev , REG_001 , 2 ) ;
2009-04-03 05:14:51 +04:00
mdelay ( 10 ) ;
2008-04-19 04:34:00 +04:00
return 0 ;
2008-04-19 05:12:52 +04:00
} else {
2008-04-19 04:34:00 +04:00
printk ( KERN_ERR
2008-04-19 04:42:30 +04:00
" %s(): Unknown command. \n " , __func__ ) ;
2008-04-19 04:34:00 +04:00
return - EINVAL ;
}
break ;
}
return 0 ; /* Should never be here */
}
2008-03-30 01:53:07 +03:00
static void hauppauge_eeprom ( struct au0828_dev * dev , u8 * eeprom_data )
{
struct tveeprom tv ;
tveeprom_hauppauge_analog ( & dev - > i2c_client , & tv , eeprom_data ) ;
2009-03-11 09:00:47 +03:00
dev - > board . tuner_type = tv . tuner_type ;
2008-03-30 01:53:07 +03:00
/* Make sure we support the board model */
2008-04-18 04:41:28 +04:00
switch ( tv . model ) {
2008-06-13 10:29:43 +04:00
case 72000 : /* WinTV-HVR950q (Retail, IR, ATSC/QAM */
2009-03-16 00:48:52 +03:00
case 72001 : /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
case 72211 : /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
case 72221 : /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
case 72231 : /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
case 72241 : /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72251 : /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
case 72301 : /* WinTV-HVR850 (Retail, IR, ATSC and analog video */
2008-06-13 10:29:43 +04:00
case 72500 : /* WinTV-HVR950q (OEM, No IR, ATSC/QAM */
2008-03-30 01:53:07 +03:00
break ;
default :
2008-04-19 04:42:30 +04:00
printk ( KERN_WARNING " %s: warning: "
" unknown hauppauge model #%d \n " , __func__ , tv . model ) ;
2008-03-30 01:53:07 +03:00
break ;
}
2008-04-19 04:42:30 +04:00
printk ( KERN_INFO " %s: hauppauge eeprom: model=%d \n " ,
__func__ , tv . model ) ;
2008-03-30 01:53:07 +03:00
}
void au0828_card_setup ( struct au0828_dev * dev )
{
static u8 eeprom [ 256 ] ;
2009-03-11 09:00:47 +03:00
struct tuner_setup tun_setup ;
2009-03-11 09:01:04 +03:00
struct v4l2_subdev * sd ;
2011-02-15 14:30:50 +03:00
unsigned int mode_mask = T_ANALOG_TV ;
2008-03-30 01:53:07 +03:00
2008-04-19 04:42:30 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2008-04-19 04:39:11 +04:00
2009-03-11 09:00:47 +03:00
memcpy ( & dev - > board , & au0828_boards [ dev - > boardnr ] , sizeof ( dev - > board ) ) ;
2008-03-30 01:53:07 +03:00
if ( dev - > i2c_rc = = 0 ) {
dev - > i2c_client . addr = 0xa0 > > 1 ;
tveeprom_read ( & dev - > i2c_client , eeprom , sizeof ( eeprom ) ) ;
}
2009-03-11 09:00:47 +03:00
switch ( dev - > boardnr ) {
2008-03-30 01:53:07 +03:00
case AU0828_BOARD_HAUPPAUGE_HVR850 :
case AU0828_BOARD_HAUPPAUGE_HVR950Q :
2008-07-09 07:23:08 +04:00
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL :
2008-09-03 23:46:36 +04:00
case AU0828_BOARD_HAUPPAUGE_WOODBURY :
2008-03-30 01:53:07 +03:00
if ( dev - > i2c_rc = = 0 )
hauppauge_eeprom ( dev , eeprom + 0xa0 ) ;
break ;
}
2009-03-11 09:00:47 +03:00
2009-03-11 09:01:01 +03:00
if ( AUVI_INPUT ( 0 ) . type ! = AU0828_VMUX_UNDEFINED ) {
2009-03-11 09:00:47 +03:00
/* Load the analog demodulator driver (note this would need to
be abstracted out if we ever need to support a different
demod ) */
2009-04-01 10:57:53 +04:00
sd = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & dev - > i2c_adap ,
2010-09-24 17:16:44 +04:00
" au8522 " , 0x8e > > 1 , NULL ) ;
2009-03-16 00:48:52 +03:00
if ( sd = = NULL )
printk ( KERN_ERR " analog subdev registration failed \n " ) ;
2009-03-11 09:00:47 +03:00
}
/* Setup tuners */
if ( dev - > board . tuner_type ! = TUNER_ABSENT ) {
/* Load the tuner module, which does the attach */
2009-04-01 10:57:53 +04:00
sd = v4l2_i2c_new_subdev ( & dev - > v4l2_dev , & dev - > i2c_adap ,
2010-09-24 17:16:44 +04:00
" tuner " , dev - > board . tuner_addr , NULL ) ;
2009-03-16 00:48:52 +03:00
if ( sd = = NULL )
printk ( KERN_ERR " tuner subdev registration fail \n " ) ;
2009-03-11 09:00:47 +03:00
tun_setup . mode_mask = mode_mask ;
tun_setup . type = dev - > board . tuner_type ;
tun_setup . addr = dev - > board . tuner_addr ;
tun_setup . tuner_callback = au0828_tuner_callback ;
2009-03-16 02:01:53 +03:00
v4l2_device_call_all ( & dev - > v4l2_dev , 0 , tuner , s_type_addr ,
& tun_setup ) ;
2009-03-11 09:00:47 +03:00
}
2008-03-30 01:53:07 +03:00
}
2008-04-19 04:34:00 +04:00
/*
* The bridge has between 8 and 12 gpios .
* Regs 1 and 0 deal with output enables .
2008-04-18 04:41:28 +04:00
* Regs 3 and 2 deal with direction .
2008-04-19 04:34:00 +04:00
*/
void au0828_gpio_setup ( struct au0828_dev * dev )
{
2008-04-19 04:42:30 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2008-04-19 04:39:11 +04:00
2009-03-11 09:00:47 +03:00
switch ( dev - > boardnr ) {
2008-04-19 04:34:00 +04:00
case AU0828_BOARD_HAUPPAUGE_HVR850 :
case AU0828_BOARD_HAUPPAUGE_HVR950Q :
2008-07-09 07:23:08 +04:00
case AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL :
2008-09-03 23:46:36 +04:00
case AU0828_BOARD_HAUPPAUGE_WOODBURY :
2008-04-19 04:34:00 +04:00
/* GPIO's
* 4 - CS5340
* 5 - AU8522 Demodulator
* 6 - eeprom W / P
2009-03-11 09:00:40 +03:00
* 7 - power supply
2008-04-19 04:34:00 +04:00
* 9 - XC5000 Tuner
*/
/* Into reset */
au0828_write ( dev , REG_003 , 0x02 ) ;
2009-03-11 09:00:40 +03:00
au0828_write ( dev , REG_002 , 0x80 | 0x20 | 0x10 ) ;
2008-04-19 04:34:00 +04:00
au0828_write ( dev , REG_001 , 0x0 ) ;
au0828_write ( dev , REG_000 , 0x0 ) ;
msleep ( 100 ) ;
2009-03-11 09:00:40 +03:00
/* Out of reset (leave the cs5340 in reset until needed) */
2008-04-19 04:34:00 +04:00
au0828_write ( dev , REG_003 , 0x02 ) ;
au0828_write ( dev , REG_001 , 0x02 ) ;
2009-03-11 09:00:40 +03:00
au0828_write ( dev , REG_002 , 0x80 | 0x20 | 0x10 ) ;
au0828_write ( dev , REG_000 , 0x80 | 0x40 | 0x20 ) ;
2008-04-19 04:34:00 +04:00
msleep ( 250 ) ;
break ;
case AU0828_BOARD_DVICO_FUSIONHDTV7 :
/* GPIO's
* 6 - ?
* 8 - AU8522 Demodulator
* 9 - XC5000 Tuner
*/
/* Into reset */
au0828_write ( dev , REG_003 , 0x02 ) ;
au0828_write ( dev , REG_002 , 0xa0 ) ;
au0828_write ( dev , REG_001 , 0x0 ) ;
au0828_write ( dev , REG_000 , 0x0 ) ;
msleep ( 100 ) ;
/* Out of reset */
au0828_write ( dev , REG_003 , 0x02 ) ;
au0828_write ( dev , REG_002 , 0xa0 ) ;
au0828_write ( dev , REG_001 , 0x02 ) ;
au0828_write ( dev , REG_000 , 0xa0 ) ;
msleep ( 250 ) ;
break ;
}
}
/* table of devices that work with this driver */
2008-10-17 03:19:41 +04:00
struct usb_device_id au0828_usb_id_table [ ] = {
2008-04-19 04:34:00 +04:00
{ USB_DEVICE ( 0x2040 , 0x7200 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
{ USB_DEVICE ( 0x2040 , 0x7240 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 } ,
{ USB_DEVICE ( 0x0fe9 , 0xd620 ) ,
. driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 } ,
2008-06-13 10:29:43 +04:00
{ USB_DEVICE ( 0x2040 , 0x7210 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
{ USB_DEVICE ( 0x2040 , 0x7217 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
{ USB_DEVICE ( 0x2040 , 0x721b ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
2008-10-16 00:00:31 +04:00
{ USB_DEVICE ( 0x2040 , 0x721e ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
2008-06-13 10:29:43 +04:00
{ USB_DEVICE ( 0x2040 , 0x721f ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
{ USB_DEVICE ( 0x2040 , 0x7280 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
{ USB_DEVICE ( 0x0fd9 , 0x0008 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
2008-07-09 07:23:08 +04:00
{ USB_DEVICE ( 0x2040 , 0x7201 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL } ,
{ USB_DEVICE ( 0x2040 , 0x7211 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL } ,
{ USB_DEVICE ( 0x2040 , 0x7281 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q_MXL } ,
2008-09-03 23:46:36 +04:00
{ USB_DEVICE ( 0x2040 , 0x8200 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY } ,
2011-11-30 01:21:41 +04:00
{ USB_DEVICE ( 0x2040 , 0x7260 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
2011-11-30 01:23:11 +04:00
{ USB_DEVICE ( 0x2040 , 0x7213 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
2008-04-19 04:34:00 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , au0828_usb_id_table ) ;