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 .
*/
# 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
2012-10-27 21:00:30 +04:00
static void hvr950q_cs5340_audio ( void * priv , int enable )
2009-03-11 09:00:40 +03:00
{
/* 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
2014-10-30 13:53:04 +03:00
/*
* WARNING : There ' s a quirks table at sound / usb / quirks - table . h
* that should also be updated every time a new device with V4L2 support
* is added here .
*/
2008-04-19 04:34:00 +04:00
struct au0828_board au0828_boards [ ] = {
[ AU0828_BOARD_UNKNOWN ] = {
. name = " Unknown board " ,
2015-01-13 05:56:55 +03:00
. tuner_type = - 1U ,
2009-03-11 09:00:47 +03:00
. 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 ,
2014-08-07 20:10:26 +04:00
. has_ir_i2c = 1 ,
2014-08-18 15:51:28 +04:00
. has_analog = 1 ,
2014-07-25 21:02:14 +04:00
. i2c_clk_divider = AU0828_I2C_CLK_250KHZ ,
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 ,
2014-07-25 05:49:02 +04:00
. has_ir_i2c = 1 ,
2014-08-18 15:51:28 +04:00
. has_analog = 1 ,
2014-07-25 21:02:14 +04:00
. i2c_clk_divider = AU0828_I2C_CLK_250KHZ ,
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 " ,
2014-08-18 15:51:29 +04:00
. tuner_type = TUNER_XC5000 ,
. tuner_addr = 0x61 ,
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 " ,
2014-08-18 15:51:29 +04:00
. tuner_type = TUNER_XC5000 ,
. tuner_addr = 0x61 ,
2014-07-25 21:02:14 +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 " ,
2014-08-18 15:51:29 +04:00
. tuner_type = TUNER_NXP_TDA18271 ,
. tuner_addr = 0x60 ,
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 {
2014-08-10 04:47:17 +04:00
pr_err ( " %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 ;
2017-03-03 13:28:29 +03:00
tveeprom_hauppauge_analog ( & 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 */
2011-11-30 01:55:04 +04:00
case 72101 : /* WinTV-HVR950q (Retail, IR, ATSC/QAM and analog video */
case 72201 : /* WinTV-HVR950q (OEM, IR, ATSC/QAM and analog video */
2009-03-16 00:48:52 +03:00
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 */
2012-11-28 18:46:24 +04:00
case 72261 : /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72271 : /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
case 72281 : /* WinTV-HVR950q (OEM, No IR, ATSC/QAM and analog video */
2009-03-16 00:48:52 +03:00
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 :
2014-08-10 04:47:17 +04:00
pr_warn ( " %s: warning: unknown hauppauge model #%d \n " ,
__func__ , tv . model ) ;
2008-03-30 01:53:07 +03:00
break ;
}
2014-08-10 04:47:17 +04:00
pr_info ( " %s: hauppauge eeprom: model=%d \n " ,
2008-04-19 04:42:30 +04:00
__func__ , tv . model ) ;
2008-03-30 01:53:07 +03:00
}
2012-12-04 19:46:38 +04:00
void au0828_card_analog_fe_setup ( struct au0828_dev * dev ) ;
2008-03-30 01:53:07 +03:00
void au0828_card_setup ( struct au0828_dev * dev )
{
static u8 eeprom [ 256 ] ;
2008-04-19 04:42:30 +04:00
dprintk ( 1 , " %s() \n " , __func__ ) ;
2008-04-19 04:39:11 +04:00
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
2012-12-04 19:46:38 +04:00
au0828_card_analog_fe_setup ( dev ) ;
}
void au0828_card_analog_fe_setup ( struct au0828_dev * dev )
{
2012-12-04 18:30:00 +04:00
# ifdef CONFIG_VIDEO_AU0828_V4L2
2012-12-04 19:46:38 +04:00
struct tuner_setup tun_setup ;
struct v4l2_subdev * sd ;
unsigned int mode_mask = T_ANALOG_TV ;
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 )
2014-08-10 04:47:17 +04:00
pr_err ( " analog subdev registration failed \n " ) ;
2009-03-11 09:00:47 +03:00
}
/* Setup tuners */
2014-08-18 15:51:28 +04:00
if ( dev - > board . tuner_type ! = TUNER_ABSENT & & dev - > board . has_analog ) {
2009-03-11 09:00:47 +03:00
/* 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 )
2014-08-10 04:47:17 +04:00
pr_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
}
2012-12-04 18:30:00 +04:00
# endif
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
*/
2013-08-20 01:25:16 +04:00
/* Set relevant GPIOs as outputs (leave the EEPROM W/P
as an input since we will never touch it and it has
a pullup ) */
2008-04-19 04:34:00 +04:00
au0828_write ( dev , REG_003 , 0x02 ) ;
2009-03-11 09:00:40 +03:00
au0828_write ( dev , REG_002 , 0x80 | 0x20 | 0x10 ) ;
2013-08-20 01:25:16 +04:00
/* Into reset */
2008-04-19 04:34:00 +04:00
au0828_write ( dev , REG_001 , 0x0 ) ;
au0828_write ( dev , REG_000 , 0x0 ) ;
2013-08-20 01:25:16 +04:00
msleep ( 50 ) ;
2008-04-19 04:34:00 +04:00
2013-08-20 01:25:16 +04:00
/* Bring power supply out of reset */
au0828_write ( dev , REG_000 , 0x80 ) ;
msleep ( 50 ) ;
/* Bring xc5000 and au8522 out of reset (leave the
cs5340 in reset until needed ) */
au0828_write ( dev , REG_001 , 0x02 ) ; /* xc5000 */
au0828_write ( dev , REG_000 , 0x80 | 0x20 ) ; /* PS + au8522 */
2009-03-11 09:00:40 +03:00
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 } ,
2012-05-11 09:14:51 +04:00
{ USB_DEVICE ( 0x05e1 , 0x0480 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_WOODBURY } ,
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 } ,
2012-11-28 08:17:50 +04:00
{ USB_DEVICE ( 0x2040 , 0x7270 ) ,
. driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q } ,
2008-04-19 04:34:00 +04:00
{ } ,
} ;
MODULE_DEVICE_TABLE ( usb , au0828_usb_id_table ) ;