2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2006-01-09 20:32:40 +03:00
/*
* Programming the mspx4xx sound processor family
*
* ( c ) 1997 - 2001 Gerd Knorr < kraxel @ bytesex . org >
*/
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/i2c.h>
2007-07-17 15:03:35 +04:00
# include <linux/freezer.h>
2006-01-09 20:32:40 +03:00
# include <linux/videodev2.h>
# include <media/v4l2-common.h>
2015-11-14 00:40:07 +03:00
# include <media/drv-intf/msp3400.h>
2006-01-09 20:32:40 +03:00
# include <linux/kthread.h>
# include <linux/suspend.h>
2006-03-19 14:45:38 +03:00
# include "msp3400-driver.h"
2006-01-09 20:32:40 +03:00
/* this one uses the automatic sound standard detection of newer msp34xx
chip versions */
static struct {
int retval ;
int main , second ;
char * name ;
2011-10-04 16:44:02 +04:00
v4l2_std_id std ;
2006-01-09 23:21:37 +03:00
} msp_stdlist [ ] = {
2011-10-04 16:44:02 +04:00
{ 0x0000 , 0 , 0 , " could not detect sound standard " , V4L2_STD_ALL } ,
{ 0x0001 , 0 , 0 , " autodetect start " , V4L2_STD_ALL } ,
{ 0x0002 , MSP_CARRIER ( 4.5 ) , MSP_CARRIER ( 4.72 ) ,
" 4.5/4.72 M Dual FM-Stereo " , V4L2_STD_MN } ,
{ 0x0003 , MSP_CARRIER ( 5.5 ) , MSP_CARRIER ( 5.7421875 ) ,
" 5.5/5.74 B/G Dual FM-Stereo " , V4L2_STD_BG } ,
{ 0x0004 , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.2578125 ) ,
" 6.5/6.25 D/K1 Dual FM-Stereo " , V4L2_STD_DK } ,
{ 0x0005 , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.7421875 ) ,
" 6.5/6.74 D/K2 Dual FM-Stereo " , V4L2_STD_DK } ,
{ 0x0006 , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.5 ) ,
" 6.5 D/K FM-Mono (HDEV3) " , V4L2_STD_DK } ,
{ 0x0007 , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 5.7421875 ) ,
" 6.5/5.74 D/K3 Dual FM-Stereo " , V4L2_STD_DK } ,
{ 0x0008 , MSP_CARRIER ( 5.5 ) , MSP_CARRIER ( 5.85 ) ,
" 5.5/5.85 B/G NICAM FM " , V4L2_STD_BG } ,
{ 0x0009 , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 5.85 ) ,
" 6.5/5.85 L NICAM AM " , V4L2_STD_L } ,
{ 0x000a , MSP_CARRIER ( 6.0 ) , MSP_CARRIER ( 6.55 ) ,
" 6.0/6.55 I NICAM FM " , V4L2_STD_PAL_I } ,
{ 0x000b , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 5.85 ) ,
" 6.5/5.85 D/K NICAM FM " , V4L2_STD_DK } ,
{ 0x000c , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 5.85 ) ,
" 6.5/5.85 D/K NICAM FM (HDEV2) " , V4L2_STD_DK } ,
{ 0x000d , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 5.85 ) ,
" 6.5/5.85 D/K NICAM FM (HDEV3) " , V4L2_STD_DK } ,
{ 0x0020 , MSP_CARRIER ( 4.5 ) , MSP_CARRIER ( 4.5 ) ,
" 4.5 M BTSC-Stereo " , V4L2_STD_MTS } ,
{ 0x0021 , MSP_CARRIER ( 4.5 ) , MSP_CARRIER ( 4.5 ) ,
" 4.5 M BTSC-Mono + SAP " , V4L2_STD_MTS } ,
{ 0x0030 , MSP_CARRIER ( 4.5 ) , MSP_CARRIER ( 4.5 ) ,
" 4.5 M EIA-J Japan Stereo " , V4L2_STD_NTSC_M_JP } ,
{ 0x0040 , MSP_CARRIER ( 10.7 ) , MSP_CARRIER ( 10.7 ) ,
" 10.7 FM-Stereo Radio " , V4L2_STD_ALL } ,
{ 0x0050 , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.5 ) ,
" 6.5 SAT-Mono " , V4L2_STD_ALL } ,
{ 0x0051 , MSP_CARRIER ( 7.02 ) , MSP_CARRIER ( 7.20 ) ,
" 7.02/7.20 SAT-Stereo " , V4L2_STD_ALL } ,
{ 0x0060 , MSP_CARRIER ( 7.2 ) , MSP_CARRIER ( 7.2 ) ,
" 7.2 SAT ADR " , V4L2_STD_ALL } ,
{ - 1 , 0 , 0 , NULL , 0 } , /* EOF */
2006-01-09 20:32:40 +03:00
} ;
static struct msp3400c_init_data_dem {
int fir1 [ 6 ] ;
int fir2 [ 6 ] ;
int cdo1 ;
int cdo2 ;
int ad_cv ;
int mode_reg ;
int dsp_src ;
int dsp_matrix ;
} msp3400c_init_data [ ] = {
{ /* AM (for carrier detect / msp3400) */
{ 75 , 19 , 36 , 35 , 39 , 40 } ,
{ 75 , 19 , 36 , 35 , 39 , 40 } ,
MSP_CARRIER ( 5.5 ) , MSP_CARRIER ( 5.5 ) ,
0x00d0 , 0x0500 , 0x0020 , 0x3000
2007-12-12 14:25:18 +03:00
} , { /* AM (for carrier detect / msp3410) */
2006-01-09 20:32:40 +03:00
{ - 1 , - 1 , - 8 , 2 , 59 , 126 } ,
{ - 1 , - 1 , - 8 , 2 , 59 , 126 } ,
MSP_CARRIER ( 5.5 ) , MSP_CARRIER ( 5.5 ) ,
0x00d0 , 0x0100 , 0x0020 , 0x3000
2007-12-12 14:25:18 +03:00
} , { /* FM Radio */
2006-01-09 20:32:40 +03:00
{ - 8 , - 8 , 4 , 6 , 78 , 107 } ,
{ - 8 , - 8 , 4 , 6 , 78 , 107 } ,
MSP_CARRIER ( 10.7 ) , MSP_CARRIER ( 10.7 ) ,
0x00d0 , 0x0480 , 0x0020 , 0x3000
2011-03-31 05:57:33 +04:00
} , { /* Terrestrial FM-mono + FM-stereo */
2006-01-09 20:32:40 +03:00
{ 3 , 18 , 27 , 48 , 66 , 72 } ,
{ 3 , 18 , 27 , 48 , 66 , 72 } ,
MSP_CARRIER ( 5.5 ) , MSP_CARRIER ( 5.5 ) ,
0x00d0 , 0x0480 , 0x0030 , 0x3000
2007-12-12 14:25:18 +03:00
} , { /* Sat FM-mono */
2006-01-09 20:32:40 +03:00
{ 1 , 9 , 14 , 24 , 33 , 37 } ,
{ 3 , 18 , 27 , 48 , 66 , 72 } ,
MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.5 ) ,
0x00c6 , 0x0480 , 0x0000 , 0x3000
2007-12-12 14:25:18 +03:00
} , { /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */
2006-01-09 20:32:40 +03:00
{ - 2 , - 8 , - 10 , 10 , 50 , 86 } ,
{ 3 , 18 , 27 , 48 , 66 , 72 } ,
MSP_CARRIER ( 5.5 ) , MSP_CARRIER ( 5.5 ) ,
0x00d0 , 0x0040 , 0x0120 , 0x3000
2007-12-12 14:25:18 +03:00
} , { /* NICAM/FM -- I (6.0/6.552) */
2006-01-09 20:32:40 +03:00
{ 2 , 4 , - 6 , - 4 , 40 , 94 } ,
{ 3 , 18 , 27 , 48 , 66 , 72 } ,
MSP_CARRIER ( 6.0 ) , MSP_CARRIER ( 6.0 ) ,
0x00d0 , 0x0040 , 0x0120 , 0x3000
2007-12-12 14:25:18 +03:00
} , { /* NICAM/AM -- L (6.5/5.85) */
2006-01-09 20:32:40 +03:00
{ - 2 , - 8 , - 10 , 10 , 50 , 86 } ,
{ - 4 , - 12 , - 9 , 23 , 79 , 126 } ,
MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.5 ) ,
2006-01-23 22:11:09 +03:00
0x00c6 , 0x0140 , 0x0120 , 0x7c00
2006-01-09 20:32:40 +03:00
} ,
} ;
struct msp3400c_carrier_detect {
int cdo ;
char * name ;
} ;
static struct msp3400c_carrier_detect msp3400c_carrier_detect_main [ ] = {
/* main carrier */
{ MSP_CARRIER ( 4.5 ) , " 4.5 NTSC " } ,
{ MSP_CARRIER ( 5.5 ) , " 5.5 PAL B/G " } ,
{ MSP_CARRIER ( 6.0 ) , " 6.0 PAL I " } ,
{ MSP_CARRIER ( 6.5 ) , " 6.5 PAL D/K + SAT + SECAM " }
} ;
static struct msp3400c_carrier_detect msp3400c_carrier_detect_55 [ ] = {
/* PAL B/G */
{ MSP_CARRIER ( 5.7421875 ) , " 5.742 PAL B/G FM-stereo " } ,
{ MSP_CARRIER ( 5.85 ) , " 5.85 PAL B/G NICAM " }
} ;
static struct msp3400c_carrier_detect msp3400c_carrier_detect_65 [ ] = {
/* PAL SAT / SECAM */
{ MSP_CARRIER ( 5.85 ) , " 5.85 PAL D/K + SECAM NICAM " } ,
{ MSP_CARRIER ( 6.2578125 ) , " 6.25 PAL D/K1 FM-stereo " } ,
{ MSP_CARRIER ( 6.7421875 ) , " 6.74 PAL D/K2 FM-stereo " } ,
{ MSP_CARRIER ( 7.02 ) , " 7.02 PAL SAT FM-stereo s/b " } ,
{ MSP_CARRIER ( 7.20 ) , " 7.20 PAL SAT FM-stereo s " } ,
{ MSP_CARRIER ( 7.38 ) , " 7.38 PAL SAT FM-stereo b " } ,
} ;
/* ------------------------------------------------------------------------ */
2006-01-09 23:21:37 +03:00
const char * msp_standard_std_name ( int std )
2006-01-09 20:32:40 +03:00
{
int i ;
2006-01-09 23:21:37 +03:00
for ( i = 0 ; msp_stdlist [ i ] . name ! = NULL ; i + + )
if ( msp_stdlist [ i ] . retval = = std )
return msp_stdlist [ i ] . name ;
2006-01-09 20:32:40 +03:00
return " unknown " ;
}
2011-10-04 16:44:02 +04:00
static v4l2_std_id msp_standard_std ( int std )
{
int i ;
for ( i = 0 ; msp_stdlist [ i ] . name ! = NULL ; i + + )
if ( msp_stdlist [ i ] . retval = = std )
return msp_stdlist [ i ] . std ;
return V4L2_STD_ALL ;
}
2006-03-08 16:50:07 +03:00
static void msp_set_source ( struct i2c_client * client , u16 src )
2006-01-23 22:11:09 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-23 22:11:09 +03:00
if ( msp_dolby ) {
msp_write_dsp ( client , 0x0008 , 0x0520 ) ; /* I2S1 */
msp_write_dsp ( client , 0x0009 , 0x0620 ) ; /* I2S2 */
} else {
msp_write_dsp ( client , 0x0008 , src ) ;
msp_write_dsp ( client , 0x0009 , src ) ;
}
msp_write_dsp ( client , 0x000a , src ) ;
msp_write_dsp ( client , 0x000b , src ) ;
msp_write_dsp ( client , 0x000c , src ) ;
2006-03-31 02:50:34 +04:00
if ( state - > has_scart2_out )
2006-01-23 22:11:09 +03:00
msp_write_dsp ( client , 0x0041 , src ) ;
}
void msp3400c_set_carrier ( struct i2c_client * client , int cdo1 , int cdo2 )
2006-01-09 20:32:40 +03:00
{
msp_write_dem ( client , 0x0093 , cdo1 & 0xfff ) ;
msp_write_dem ( client , 0x009b , cdo1 > > 12 ) ;
msp_write_dem ( client , 0x00a3 , cdo2 & 0xfff ) ;
msp_write_dem ( client , 0x00ab , cdo2 > > 12 ) ;
2006-01-23 22:11:09 +03:00
msp_write_dem ( client , 0x0056 , 0 ) ; /* LOAD_REG_1/2 */
2006-01-09 20:32:40 +03:00
}
2006-01-23 22:11:09 +03:00
void msp3400c_set_mode ( struct i2c_client * client , int mode )
2006-01-09 20:32:40 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-23 22:11:09 +03:00
struct msp3400c_init_data_dem * data = & msp3400c_init_data [ mode ] ;
2009-04-02 18:26:22 +04:00
int tuner = ( state - > route_in > > 3 ) & 1 ;
2006-01-09 20:32:40 +03:00
int i ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " set_mode: %d \n " , mode ) ;
2006-01-23 22:11:09 +03:00
state - > mode = mode ;
2006-01-09 20:32:40 +03:00
state - > rxsubchans = V4L2_TUNER_SUB_MONO ;
2006-03-19 18:35:57 +03:00
msp_write_dem ( client , 0x00bb , data - > ad_cv | ( tuner ? 0x100 : 0 ) ) ;
2006-01-09 20:32:40 +03:00
for ( i = 5 ; i > = 0 ; i - - ) /* fir 1 */
2006-01-23 22:11:09 +03:00
msp_write_dem ( client , 0x0001 , data - > fir1 [ i ] ) ;
2006-01-09 20:32:40 +03:00
msp_write_dem ( client , 0x0005 , 0x0004 ) ; /* fir 2 */
msp_write_dem ( client , 0x0005 , 0x0040 ) ;
msp_write_dem ( client , 0x0005 , 0x0000 ) ;
for ( i = 5 ; i > = 0 ; i - - )
2006-01-23 22:11:09 +03:00
msp_write_dem ( client , 0x0005 , data - > fir2 [ i ] ) ;
2006-01-09 20:32:40 +03:00
2006-01-23 22:11:09 +03:00
msp_write_dem ( client , 0x0083 , data - > mode_reg ) ;
2006-01-09 20:32:40 +03:00
2006-01-23 22:11:09 +03:00
msp3400c_set_carrier ( client , data - > cdo1 , data - > cdo2 ) ;
2006-01-09 20:32:40 +03:00
2006-01-23 22:11:09 +03:00
msp_set_source ( client , data - > dsp_src ) ;
2006-03-19 14:21:56 +03:00
/* set prescales */
2006-01-09 20:32:40 +03:00
2006-03-19 14:21:56 +03:00
/* volume prescale for SCART (AM mono input) */
msp_write_dsp ( client , 0x000d , 0x1900 ) ;
msp_write_dsp ( client , 0x000e , data - > dsp_matrix ) ;
if ( state - > has_nicam ) /* nicam prescale */
msp_write_dsp ( client , 0x0010 , 0x5a00 ) ;
2006-01-09 20:32:40 +03:00
}
2006-01-23 22:11:09 +03:00
/* Set audio mode. Note that the pre-'G' models do not support BTSC+SAP,
nor do they support stereo BTSC . */
2006-03-08 16:50:07 +03:00
static void msp3400c_set_audmode ( struct i2c_client * client )
2006-01-09 20:32:40 +03:00
{
2007-12-12 14:25:18 +03:00
static char * strmode [ ] = {
" mono " , " stereo " , " lang2 " , " lang1 " , " lang1+lang2 "
} ;
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-03-18 23:15:00 +03:00
char * modestr = ( state - > audmode > = 0 & & state - > audmode < 5 ) ?
2006-01-23 22:11:09 +03:00
strmode [ state - > audmode ] : " unknown " ;
int src = 0 ; /* channel source: FM/AM, nicam or SCART */
2006-03-29 21:31:44 +04:00
int audmode = state - > audmode ;
2006-01-09 20:32:40 +03:00
if ( state - > opmode = = OPMODE_AUTOSELECT ) {
/* this method would break everything, let's make sure
* it ' s never called
*/
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2006-01-23 22:11:09 +03:00
" set_audmode called with mode=%d instead of set_source (ignored) \n " ,
state - > audmode ) ;
2006-01-09 20:32:40 +03:00
return ;
}
2006-03-31 02:50:34 +04:00
/* Note: for the C and D revs no NTSC stereo + SAP is possible as
the hardware does not support SAP . So the rxsubchans combination
of STEREO | LANG2 does not occur . */
2006-04-02 15:21:02 +04:00
if ( state - > mode ! = MSP_MODE_EXTERN ) {
/* switch to mono if only mono is available */
if ( state - > rxsubchans = = V4L2_TUNER_SUB_MONO )
audmode = V4L2_TUNER_MODE_MONO ;
/* if bilingual */
else if ( state - > rxsubchans & V4L2_TUNER_SUB_LANG2 ) {
/* and mono or stereo, then fallback to lang1 */
if ( audmode = = V4L2_TUNER_MODE_MONO | |
audmode = = V4L2_TUNER_MODE_STEREO )
audmode = V4L2_TUNER_MODE_LANG1 ;
}
/* if stereo, and audmode is not mono, then switch to stereo */
else if ( audmode ! = V4L2_TUNER_MODE_MONO )
audmode = V4L2_TUNER_MODE_STEREO ;
2006-03-31 02:50:34 +04:00
}
2006-03-29 21:31:44 +04:00
2006-01-09 20:32:40 +03:00
/* switch demodulator */
switch ( state - > mode ) {
case MSP_MODE_FM_TERRA :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " FM set_audmode: %s \n " , modestr ) ;
2006-03-29 21:31:44 +04:00
switch ( audmode ) {
2006-01-09 20:32:40 +03:00
case V4L2_TUNER_MODE_STEREO :
msp_write_dsp ( client , 0x000e , 0x3001 ) ;
break ;
case V4L2_TUNER_MODE_MONO :
case V4L2_TUNER_MODE_LANG1 :
case V4L2_TUNER_MODE_LANG2 :
2006-03-18 23:15:00 +03:00
case V4L2_TUNER_MODE_LANG1_LANG2 :
2006-01-09 20:32:40 +03:00
msp_write_dsp ( client , 0x000e , 0x3000 ) ;
break ;
}
break ;
case MSP_MODE_FM_SAT :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " SAT set_audmode: %s \n " , modestr ) ;
2006-03-29 21:31:44 +04:00
switch ( audmode ) {
2006-01-09 20:32:40 +03:00
case V4L2_TUNER_MODE_MONO :
2006-01-23 22:11:09 +03:00
msp3400c_set_carrier ( client , MSP_CARRIER ( 6.5 ) , MSP_CARRIER ( 6.5 ) ) ;
2006-01-09 20:32:40 +03:00
break ;
case V4L2_TUNER_MODE_STEREO :
2006-03-18 23:15:00 +03:00
case V4L2_TUNER_MODE_LANG1_LANG2 :
2006-01-23 22:11:09 +03:00
msp3400c_set_carrier ( client , MSP_CARRIER ( 7.2 ) , MSP_CARRIER ( 7.02 ) ) ;
2006-01-09 20:32:40 +03:00
break ;
case V4L2_TUNER_MODE_LANG1 :
2006-01-23 22:11:09 +03:00
msp3400c_set_carrier ( client , MSP_CARRIER ( 7.38 ) , MSP_CARRIER ( 7.02 ) ) ;
2006-01-09 20:32:40 +03:00
break ;
case V4L2_TUNER_MODE_LANG2 :
2006-01-23 22:11:09 +03:00
msp3400c_set_carrier ( client , MSP_CARRIER ( 7.38 ) , MSP_CARRIER ( 7.02 ) ) ;
2006-01-09 20:32:40 +03:00
break ;
}
break ;
case MSP_MODE_FM_NICAM1 :
case MSP_MODE_FM_NICAM2 :
case MSP_MODE_AM_NICAM :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" NICAM set_audmode: %s \n " , modestr ) ;
2006-01-09 20:32:40 +03:00
if ( state - > nicam_on )
2006-01-23 22:11:09 +03:00
src = 0x0100 ; /* NICAM */
2006-01-09 20:32:40 +03:00
break ;
case MSP_MODE_BTSC :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" BTSC set_audmode: %s \n " , modestr ) ;
2006-01-09 20:32:40 +03:00
break ;
case MSP_MODE_EXTERN :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" extern set_audmode: %s \n " , modestr ) ;
2006-01-23 22:11:09 +03:00
src = 0x0200 ; /* SCART */
2006-01-09 20:32:40 +03:00
break ;
case MSP_MODE_FM_RADIO :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" FM-Radio set_audmode: %s \n " , modestr ) ;
2006-01-09 20:32:40 +03:00
break ;
default :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " mono set_audmode \n " ) ;
2006-01-09 20:32:40 +03:00
return ;
}
/* switch audio */
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " set audmode %d \n " , audmode ) ;
2006-03-29 21:31:44 +04:00
switch ( audmode ) {
2006-01-09 20:32:40 +03:00
case V4L2_TUNER_MODE_STEREO :
2006-03-18 23:15:00 +03:00
case V4L2_TUNER_MODE_LANG1_LANG2 :
2006-01-23 22:11:09 +03:00
src | = 0x0020 ;
2006-01-09 20:32:40 +03:00
break ;
case V4L2_TUNER_MODE_MONO :
if ( state - > mode = = MSP_MODE_AM_NICAM ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " switching to AM mono \n " ) ;
2006-01-09 20:32:40 +03:00
/* AM mono decoding is handled by tuner, not MSP chip */
/* SCART switching control register */
msp_set_scart ( client , SCART_MONO , 0 ) ;
src = 0x0200 ;
break ;
}
2006-01-23 22:11:09 +03:00
if ( state - > rxsubchans & V4L2_TUNER_SUB_STEREO )
src = 0x0030 ;
break ;
2006-01-09 20:32:40 +03:00
case V4L2_TUNER_MODE_LANG1 :
break ;
case V4L2_TUNER_MODE_LANG2 :
2006-01-23 22:11:09 +03:00
src | = 0x0010 ;
2006-01-09 20:32:40 +03:00
break ;
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" set_audmode final source/matrix = 0x%x \n " , src ) ;
2006-01-09 20:32:40 +03:00
2006-01-23 22:11:09 +03:00
msp_set_source ( client , src ) ;
2006-01-09 20:32:40 +03:00
}
static void msp3400c_print_mode ( struct i2c_client * client )
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-09 20:32:40 +03:00
2007-12-12 14:25:18 +03:00
if ( state - > main = = state - > second )
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" mono sound carrier: %d.%03d MHz \n " ,
state - > main / 910000 , ( state - > main / 910 ) % 1000 ) ;
else
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" main sound carrier: %d.%03d MHz \n " ,
state - > main / 910000 , ( state - > main / 910 ) % 1000 ) ;
2006-01-09 20:32:40 +03:00
if ( state - > mode = = MSP_MODE_FM_NICAM1 | | state - > mode = = MSP_MODE_FM_NICAM2 )
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" NICAM/FM carrier : %d.%03d MHz \n " ,
state - > second / 910000 , ( state - > second / 910 ) % 1000 ) ;
2006-01-09 20:32:40 +03:00
if ( state - > mode = = MSP_MODE_AM_NICAM )
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" NICAM/AM carrier : %d.%03d MHz \n " ,
state - > second / 910000 , ( state - > second / 910 ) % 1000 ) ;
2006-01-09 20:32:40 +03:00
if ( state - > mode = = MSP_MODE_FM_TERRA & & state - > main ! = state - > second ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" FM-stereo carrier : %d.%03d MHz \n " ,
state - > second / 910000 , ( state - > second / 910 ) % 1000 ) ;
2006-01-09 20:32:40 +03:00
}
}
/* ----------------------------------------------------------------------- */
2006-01-23 22:11:09 +03:00
static int msp3400c_detect_stereo ( struct i2c_client * client )
2006-01-09 20:32:40 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-09 20:32:40 +03:00
int val ;
int rxsubchans = state - > rxsubchans ;
2006-01-23 22:11:09 +03:00
int newnicam = state - > nicam_on ;
2006-01-09 20:32:40 +03:00
int update = 0 ;
switch ( state - > mode ) {
case MSP_MODE_FM_TERRA :
val = msp_read_dsp ( client , 0x18 ) ;
if ( val > 32767 )
val - = 65536 ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug ,
2007-12-12 14:25:18 +03:00
" stereo detect register: %d \n " , val ) ;
2006-04-01 22:27:52 +04:00
if ( val > 8192 ) {
2006-01-23 22:11:09 +03:00
rxsubchans = V4L2_TUNER_SUB_STEREO ;
2006-01-09 20:32:40 +03:00
} else if ( val < - 4096 ) {
rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2 ;
} else {
rxsubchans = V4L2_TUNER_SUB_MONO ;
}
newnicam = 0 ;
break ;
case MSP_MODE_FM_NICAM1 :
case MSP_MODE_FM_NICAM2 :
case MSP_MODE_AM_NICAM :
val = msp_read_dem ( client , 0x23 ) ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " nicam sync=%d, mode=%d \n " ,
2006-01-09 20:32:40 +03:00
val & 1 , ( val & 0x1e ) > > 1 ) ;
if ( val & 1 ) {
/* nicam synced */
switch ( ( val & 0x1e ) > > 1 ) {
case 0 :
case 8 :
rxsubchans = V4L2_TUNER_SUB_STEREO ;
break ;
case 1 :
case 9 :
2006-01-23 22:11:09 +03:00
rxsubchans = V4L2_TUNER_SUB_MONO ;
2006-01-09 20:32:40 +03:00
break ;
case 2 :
case 10 :
2006-01-23 22:11:09 +03:00
rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2 ;
2006-01-09 20:32:40 +03:00
break ;
default :
rxsubchans = V4L2_TUNER_SUB_MONO ;
break ;
}
newnicam = 1 ;
} else {
newnicam = 0 ;
rxsubchans = V4L2_TUNER_SUB_MONO ;
}
break ;
}
if ( rxsubchans ! = state - > rxsubchans ) {
update = 1 ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" watch: rxsubchans %02x => %02x \n " ,
2006-01-23 22:11:09 +03:00
state - > rxsubchans , rxsubchans ) ;
2006-01-09 20:32:40 +03:00
state - > rxsubchans = rxsubchans ;
}
if ( newnicam ! = state - > nicam_on ) {
update = 1 ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " watch: nicam %d => %d \n " ,
2006-01-23 22:11:09 +03:00
state - > nicam_on , newnicam ) ;
2006-01-09 20:32:40 +03:00
state - > nicam_on = newnicam ;
}
return update ;
}
/*
* A kernel thread for msp3400 control - - we don ' t want to block the
* in the ioctl while doing the sound carrier & stereo detect
*/
/* stereo/multilang monitoring */
static void watch_stereo ( struct i2c_client * client )
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-09 20:32:40 +03:00
2007-12-12 14:25:18 +03:00
if ( msp_detect_stereo ( client ) )
2006-03-19 14:21:56 +03:00
msp_set_audmode ( client ) ;
2006-01-09 20:32:40 +03:00
2006-01-12 00:41:49 +03:00
if ( msp_once )
2006-01-09 20:32:40 +03:00
state - > watch_stereo = 0 ;
}
int msp3400c_thread ( void * data )
{
struct i2c_client * client = data ;
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-09 20:32:40 +03:00
struct msp3400c_carrier_detect * cd ;
2007-12-12 14:25:18 +03:00
int count , max1 , max2 , val1 , val2 , val , i ;
2006-01-09 20:32:40 +03:00
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " msp3400 daemon started \n " ) ;
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_ALL ;
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2006-01-09 20:32:40 +03:00
for ( ; ; ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " msp3400 thread: sleep \n " ) ;
2006-01-09 20:32:40 +03:00
msp_sleep ( state , - 1 ) ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " msp3400 thread: wakeup \n " ) ;
2006-01-09 20:32:40 +03:00
2007-12-12 14:25:18 +03:00
restart :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " thread: restart scan \n " ) ;
2006-01-09 20:32:40 +03:00
state - > restart = 0 ;
if ( kthread_should_stop ( ) )
break ;
2006-01-09 23:21:32 +03:00
if ( state - > radio | | MSP_MODE_EXTERN = = state - > mode ) {
2006-01-09 20:32:40 +03:00
/* no carrier scan, just unmute */
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" thread: no carrier scan \n " ) ;
2006-04-01 22:27:52 +04:00
state - > scan_in_progress = 0 ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-01-09 20:32:40 +03:00
continue ;
}
2006-04-01 22:27:52 +04:00
/* mute audio */
state - > scan_in_progress = 1 ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-03-31 02:50:34 +04:00
2006-03-19 14:21:56 +03:00
msp3400c_set_mode ( client , MSP_MODE_AM_DETECT ) ;
2006-01-09 20:32:40 +03:00
val1 = val2 = 0 ;
max1 = max2 = - 1 ;
state - > watch_stereo = 0 ;
2006-01-23 22:11:09 +03:00
state - > nicam_on = 0 ;
2006-01-09 20:32:40 +03:00
2006-04-01 22:27:52 +04:00
/* wait for tuner to settle down after a channel change */
2006-01-23 22:11:09 +03:00
if ( msp_sleep ( state , 200 ) )
2006-01-09 20:32:40 +03:00
goto restart ;
/* carrier detect pass #1 -- main carrier */
cd = msp3400c_carrier_detect_main ;
count = ARRAY_SIZE ( msp3400c_carrier_detect_main ) ;
2006-01-12 00:41:49 +03:00
if ( msp_amsound & & ( state - > v4l2_std & V4L2_STD_SECAM ) ) {
2006-01-09 20:32:40 +03:00
/* autodetect doesn't work well with AM ... */
max1 = 3 ;
count = 0 ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " AM sound override \n " ) ;
2006-01-09 20:32:40 +03:00
}
2007-12-12 14:25:18 +03:00
for ( i = 0 ; i < count ; i + + ) {
msp3400c_set_carrier ( client , cd [ i ] . cdo , cd [ i ] . cdo ) ;
if ( msp_sleep ( state , 100 ) )
2006-01-09 20:32:40 +03:00
goto restart ;
val = msp_read_dsp ( client , 0x1b ) ;
if ( val > 32767 )
val - = 65536 ;
2020-09-29 16:14:35 +03:00
if ( val1 < val ) {
val1 = val ;
max1 = i ;
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" carrier1 val: %5d / %s \n " , val , cd [ i ] . name ) ;
2006-01-09 20:32:40 +03:00
}
/* carrier detect pass #2 -- second (stereo) carrier */
switch ( max1 ) {
case 1 : /* 5.5 */
cd = msp3400c_carrier_detect_55 ;
count = ARRAY_SIZE ( msp3400c_carrier_detect_55 ) ;
break ;
case 3 : /* 6.5 */
cd = msp3400c_carrier_detect_65 ;
count = ARRAY_SIZE ( msp3400c_carrier_detect_65 ) ;
break ;
case 0 : /* 4.5 */
case 2 : /* 6.0 */
default :
cd = NULL ;
count = 0 ;
break ;
}
2006-01-12 00:41:49 +03:00
if ( msp_amsound & & ( state - > v4l2_std & V4L2_STD_SECAM ) ) {
2006-01-09 20:32:40 +03:00
/* autodetect doesn't work well with AM ... */
cd = NULL ;
count = 0 ;
max2 = 0 ;
}
2007-12-12 14:25:18 +03:00
for ( i = 0 ; i < count ; i + + ) {
msp3400c_set_carrier ( client , cd [ i ] . cdo , cd [ i ] . cdo ) ;
if ( msp_sleep ( state , 100 ) )
2006-01-09 20:32:40 +03:00
goto restart ;
val = msp_read_dsp ( client , 0x1b ) ;
if ( val > 32767 )
val - = 65536 ;
2020-09-29 16:14:35 +03:00
if ( val2 < val ) {
val2 = val ;
max2 = i ;
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" carrier2 val: %5d / %s \n " , val , cd [ i ] . name ) ;
2006-01-09 20:32:40 +03:00
}
/* program the msp3400 according to the results */
2006-01-23 22:11:09 +03:00
state - > main = msp3400c_carrier_detect_main [ max1 ] . cdo ;
2006-01-09 20:32:40 +03:00
switch ( max1 ) {
case 1 : /* 5.5 */
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_BG | V4L2_STD_PAL_H ;
2006-01-09 20:32:40 +03:00
if ( max2 = = 0 ) {
/* B/G FM-stereo */
state - > second = msp3400c_carrier_detect_55 [ max2 ] . cdo ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_TERRA ) ;
2006-01-09 20:32:40 +03:00
state - > watch_stereo = 1 ;
2006-01-09 23:21:32 +03:00
} else if ( max2 = = 1 & & state - > has_nicam ) {
2006-01-09 20:32:40 +03:00
/* B/G NICAM */
state - > second = msp3400c_carrier_detect_55 [ max2 ] . cdo ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_NICAM1 ) ;
2006-01-09 20:32:40 +03:00
state - > nicam_on = 1 ;
state - > watch_stereo = 1 ;
} else {
goto no_second ;
}
break ;
case 2 : /* 6.0 */
/* PAL I NICAM */
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_PAL_I ;
2006-01-09 20:32:40 +03:00
state - > second = MSP_CARRIER ( 6.552 ) ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_NICAM2 ) ;
2006-01-09 20:32:40 +03:00
state - > nicam_on = 1 ;
state - > watch_stereo = 1 ;
break ;
case 3 : /* 6.5 */
if ( max2 = = 1 | | max2 = = 2 ) {
/* D/K FM-stereo */
state - > second = msp3400c_carrier_detect_65 [ max2 ] . cdo ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_TERRA ) ;
2006-01-09 20:32:40 +03:00
state - > watch_stereo = 1 ;
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_DK ;
2006-01-09 23:21:37 +03:00
} else if ( max2 = = 0 & & ( state - > v4l2_std & V4L2_STD_SECAM ) ) {
2006-01-09 20:32:40 +03:00
/* L NICAM or AM-mono */
state - > second = msp3400c_carrier_detect_65 [ max2 ] . cdo ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_AM_NICAM ) ;
2006-01-09 20:32:40 +03:00
state - > watch_stereo = 1 ;
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_L ;
2006-01-09 23:21:32 +03:00
} else if ( max2 = = 0 & & state - > has_nicam ) {
2006-01-09 20:32:40 +03:00
/* D/K NICAM */
state - > second = msp3400c_carrier_detect_65 [ max2 ] . cdo ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_NICAM1 ) ;
2006-01-09 20:32:40 +03:00
state - > nicam_on = 1 ;
state - > watch_stereo = 1 ;
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_DK ;
2006-01-09 20:32:40 +03:00
} else {
goto no_second ;
}
break ;
case 0 : /* 4.5 */
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_MN ;
2020-07-25 01:10:14 +03:00
fallthrough ;
2006-01-09 20:32:40 +03:00
default :
2007-12-12 14:25:18 +03:00
no_second :
2006-01-09 20:32:40 +03:00
state - > second = msp3400c_carrier_detect_main [ max1 ] . cdo ;
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_TERRA ) ;
2006-01-09 20:32:40 +03:00
break ;
}
2006-03-31 02:50:34 +04:00
msp3400c_set_carrier ( client , state - > second , state - > main ) ;
2006-01-09 20:32:40 +03:00
2006-04-01 22:27:52 +04:00
/* unmute */
state - > scan_in_progress = 0 ;
2006-01-23 22:11:09 +03:00
msp3400c_set_audmode ( client ) ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-01-09 20:32:40 +03:00
2006-01-12 00:41:49 +03:00
if ( msp_debug )
2006-01-09 20:32:40 +03:00
msp3400c_print_mode ( client ) ;
2006-01-23 22:11:09 +03:00
/* monitor tv audio mode, the first time don't wait
so long to get a quick stereo / bilingual result */
2006-04-01 22:27:52 +04:00
count = 3 ;
2006-01-09 20:32:40 +03:00
while ( state - > watch_stereo ) {
2006-04-01 22:27:52 +04:00
if ( msp_sleep ( state , count ? 1000 : 5000 ) )
2006-01-09 20:32:40 +03:00
goto restart ;
2007-12-12 14:25:18 +03:00
if ( count )
count - - ;
2006-04-01 22:27:52 +04:00
watch_stereo ( client ) ;
2006-01-09 20:32:40 +03:00
}
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " thread: exit \n " ) ;
2006-01-09 20:32:40 +03:00
return 0 ;
}
int msp3410d_thread ( void * data )
{
struct i2c_client * client = data ;
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-03-31 02:50:34 +04:00
int val , i , std , count ;
2006-01-09 20:32:40 +03:00
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " msp3410 daemon started \n " ) ;
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_ALL ;
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2006-01-09 20:32:40 +03:00
for ( ; ; ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " msp3410 thread: sleep \n " ) ;
2007-12-12 14:25:18 +03:00
msp_sleep ( state , - 1 ) ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " msp3410 thread: wakeup \n " ) ;
2006-01-09 20:32:40 +03:00
2007-12-12 14:25:18 +03:00
restart :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " thread: restart scan \n " ) ;
2006-01-09 20:32:40 +03:00
state - > restart = 0 ;
if ( kthread_should_stop ( ) )
break ;
if ( state - > mode = = MSP_MODE_EXTERN ) {
/* no carrier scan needed, just unmute */
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" thread: no carrier scan \n " ) ;
2006-04-01 22:27:52 +04:00
state - > scan_in_progress = 0 ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-01-09 20:32:40 +03:00
continue ;
}
2006-04-01 22:27:52 +04:00
/* mute audio */
state - > scan_in_progress = 1 ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-01-09 20:32:40 +03:00
2006-03-19 14:21:56 +03:00
/* start autodetect. Note: autodetect is not supported for
2007-12-12 14:25:18 +03:00
NTSC - M and radio , hence we force the standard in those
cases . */
2006-01-09 23:21:37 +03:00
if ( state - > radio )
std = 0x40 ;
2006-01-09 23:21:36 +03:00
else
2006-01-09 23:21:37 +03:00
std = ( state - > v4l2_std & V4L2_STD_NTSC ) ? 0x20 : 1 ;
2006-01-09 20:32:40 +03:00
state - > watch_stereo = 0 ;
2006-01-23 22:11:09 +03:00
state - > nicam_on = 0 ;
2006-01-09 20:32:40 +03:00
2006-04-01 22:27:52 +04:00
/* wait for tuner to settle down after a channel change */
if ( msp_sleep ( state , 200 ) )
goto restart ;
2006-01-12 00:41:49 +03:00
if ( msp_debug )
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug ,
2007-12-12 14:25:18 +03:00
" setting standard: %s (0x%04x) \n " ,
msp_standard_std_name ( std ) , std ) ;
2006-01-09 20:32:40 +03:00
if ( std ! = 1 ) {
/* programmed some specific mode */
val = std ;
} else {
/* triggered autodetect */
2006-01-09 23:21:37 +03:00
msp_write_dem ( client , 0x20 , std ) ;
2006-01-09 20:32:40 +03:00
for ( ; ; ) {
2006-01-09 23:21:36 +03:00
if ( msp_sleep ( state , 100 ) )
2006-01-09 20:32:40 +03:00
goto restart ;
/* check results */
val = msp_read_dem ( client , 0x7e ) ;
if ( val < 0x07ff )
break ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug ,
2007-12-12 14:25:18 +03:00
" detection still in progress \n " ) ;
2006-01-09 20:32:40 +03:00
}
}
2006-01-09 23:21:37 +03:00
for ( i = 0 ; msp_stdlist [ i ] . name ! = NULL ; i + + )
if ( msp_stdlist [ i ] . retval = = val )
2006-01-09 20:32:40 +03:00
break ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " current standard: %s (0x%04x) \n " ,
2006-01-09 23:21:37 +03:00
msp_standard_std_name ( val ) , val ) ;
state - > main = msp_stdlist [ i ] . main ;
state - > second = msp_stdlist [ i ] . second ;
state - > std = val ;
2006-04-01 22:27:52 +04:00
state - > rxsubchans = V4L2_TUNER_SUB_MONO ;
2006-01-09 23:21:37 +03:00
2007-12-12 14:25:18 +03:00
if ( msp_amsound & & ! state - > radio & &
( state - > v4l2_std & V4L2_STD_SECAM ) & & ( val ! = 0x0009 ) ) {
2006-01-09 20:32:40 +03:00
/* autodetection has failed, let backup */
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " autodetection failed, switching to backup standard: %s (0x%04x) \n " ,
2007-12-12 14:25:18 +03:00
msp_stdlist [ 8 ] . name ?
msp_stdlist [ 8 ] . name : " unknown " , val ) ;
2006-03-19 14:21:56 +03:00
state - > std = val = 0x0009 ;
2006-01-09 20:32:40 +03:00
msp_write_dem ( client , 0x20 , val ) ;
2011-10-04 16:44:02 +04:00
} else {
state - > detected_std = msp_standard_std ( state - > std ) ;
2006-01-09 20:32:40 +03:00
}
/* set stereo */
switch ( val ) {
case 0x0008 : /* B/G NICAM */
case 0x000a : /* I NICAM */
2006-03-19 14:21:56 +03:00
case 0x000b : /* D/K NICAM */
if ( val = = 0x000a )
2006-01-09 20:32:40 +03:00
state - > mode = MSP_MODE_FM_NICAM2 ;
2006-03-19 14:21:56 +03:00
else
state - > mode = MSP_MODE_FM_NICAM1 ;
2006-01-09 20:32:40 +03:00
/* just turn on stereo */
state - > nicam_on = 1 ;
state - > watch_stereo = 1 ;
break ;
case 0x0009 :
state - > mode = MSP_MODE_AM_NICAM ;
state - > nicam_on = 1 ;
state - > watch_stereo = 1 ;
break ;
case 0x0020 : /* BTSC */
2006-01-23 22:11:09 +03:00
/* The pre-'G' models only have BTSC-mono */
2006-01-09 20:32:40 +03:00
state - > mode = MSP_MODE_BTSC ;
break ;
case 0x0040 : /* FM radio */
2006-01-09 23:21:32 +03:00
state - > mode = MSP_MODE_FM_RADIO ;
2006-01-09 20:32:40 +03:00
state - > rxsubchans = V4L2_TUNER_SUB_STEREO ;
2006-01-09 23:21:32 +03:00
/* not needed in theory if we have radio, but
2006-01-09 20:32:40 +03:00
short programming enables carrier mute */
2006-01-23 22:11:09 +03:00
msp3400c_set_mode ( client , MSP_MODE_FM_RADIO ) ;
msp3400c_set_carrier ( client , MSP_CARRIER ( 10.7 ) ,
2006-01-09 20:32:40 +03:00
MSP_CARRIER ( 10.7 ) ) ;
break ;
2006-03-19 14:21:56 +03:00
case 0x0002 :
2006-01-09 20:32:40 +03:00
case 0x0003 :
case 0x0004 :
case 0x0005 :
2006-01-09 23:21:37 +03:00
state - > mode = MSP_MODE_FM_TERRA ;
2006-01-09 20:32:40 +03:00
state - > watch_stereo = 1 ;
break ;
}
2006-03-19 14:21:56 +03:00
/* set various prescales */
msp_write_dsp ( client , 0x0d , 0x1900 ) ; /* scart */
msp_write_dsp ( client , 0x0e , 0x3000 ) ; /* FM */
if ( state - > has_nicam )
msp_write_dsp ( client , 0x10 , 0x5a00 ) ; /* nicam */
2006-01-09 23:21:37 +03:00
if ( state - > has_i2s_conf )
msp_write_dem ( client , 0x40 , state - > i2s_mode ) ;
2006-01-09 20:32:40 +03:00
2006-04-01 22:27:52 +04:00
/* unmute */
2006-01-23 22:11:09 +03:00
msp3400c_set_audmode ( client ) ;
2006-04-01 22:27:52 +04:00
state - > scan_in_progress = 0 ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-01-23 22:11:09 +03:00
/* monitor tv audio mode, the first time don't wait
so long to get a quick stereo / bilingual result */
2006-04-01 22:27:52 +04:00
count = 3 ;
2006-01-09 20:32:40 +03:00
while ( state - > watch_stereo ) {
2006-04-01 22:27:52 +04:00
if ( msp_sleep ( state , count ? 1000 : 5000 ) )
2006-01-23 22:11:09 +03:00
goto restart ;
2007-12-12 14:25:18 +03:00
if ( count )
count - - ;
2006-04-01 22:27:52 +04:00
watch_stereo ( client ) ;
2006-01-09 20:32:40 +03:00
}
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " thread: exit \n " ) ;
2006-01-09 20:32:40 +03:00
return 0 ;
}
/* ----------------------------------------------------------------------- */
2006-03-19 14:21:56 +03:00
/* msp34xxG + (autoselect no-thread)
* this one uses both automatic standard detection and automatic sound
* select which are available in the newer G versions
* struct msp : only norm , acb and source are really used in this mode
*/
2006-01-09 20:32:40 +03:00
2006-03-19 13:25:42 +03:00
static int msp34xxg_modus ( struct i2c_client * client )
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-03-19 13:25:42 +03:00
if ( state - > radio ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " selected radio modus \n " ) ;
2006-03-19 13:25:42 +03:00
return 0x0001 ;
}
if ( state - > v4l2_std = = V4L2_STD_NTSC_M_JP ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " selected M (EIA-J) modus \n " ) ;
2006-03-19 13:25:42 +03:00
return 0x4001 ;
}
if ( state - > v4l2_std = = V4L2_STD_NTSC_M_KR ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " selected M (A2) modus \n " ) ;
2006-03-19 13:25:42 +03:00
return 0x0001 ;
}
2008-04-22 21:45:51 +04:00
if ( state - > v4l2_std = = V4L2_STD_SECAM_L ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " selected SECAM-L modus \n " ) ;
2008-04-22 21:45:51 +04:00
return 0x6001 ;
}
2006-03-19 13:25:42 +03:00
if ( state - > v4l2_std & V4L2_STD_MN ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " selected M (BTSC) modus \n " ) ;
2006-03-19 13:25:42 +03:00
return 0x2001 ;
}
2008-04-22 21:45:51 +04:00
return 0x7001 ;
2006-03-19 13:25:42 +03:00
}
2006-03-19 18:35:57 +03:00
static void msp34xxg_set_source ( struct i2c_client * client , u16 reg , int in )
2018-03-22 01:09:32 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-03-19 18:35:57 +03:00
int source , matrix ;
switch ( state - > audmode ) {
case V4L2_TUNER_MODE_MONO :
source = 0 ; /* mono only */
matrix = 0x30 ;
break ;
case V4L2_TUNER_MODE_LANG2 :
source = 4 ; /* stereo or B */
matrix = 0x10 ;
break ;
2006-03-18 23:15:00 +03:00
case V4L2_TUNER_MODE_LANG1_LANG2 :
2006-03-19 18:35:57 +03:00
source = 1 ; /* stereo or A|B */
matrix = 0x20 ;
break ;
2006-03-31 02:50:34 +04:00
case V4L2_TUNER_MODE_LANG1 :
source = 3 ; /* stereo or A */
matrix = 0x00 ;
break ;
2006-12-18 19:18:28 +03:00
case V4L2_TUNER_MODE_STEREO :
default :
source = 3 ; /* stereo or A */
matrix = 0x20 ;
break ;
2006-03-19 18:35:57 +03:00
}
2006-04-02 01:03:23 +04:00
if ( in = = MSP_DSP_IN_TUNER )
2006-03-19 18:35:57 +03:00
source = ( source < < 8 ) | 0x20 ;
/* the msp34x2g puts the MAIN_AVC, MAIN and AUX sources in 12, 13, 14
instead of 11 , 12 , 13. So we add one for that msp version . */
2006-04-02 01:03:23 +04:00
else if ( in > = MSP_DSP_IN_MAIN_AVC & & state - > has_dolby_pro_logic )
2006-03-19 18:35:57 +03:00
source = ( ( in + 1 ) < < 8 ) | matrix ;
else
source = ( in < < 8 ) | matrix ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" set source to %d (0x%x) for output %02x \n " , in , source , reg ) ;
2006-03-19 18:35:57 +03:00
msp_write_dsp ( client , reg , source ) ;
}
static void msp34xxg_set_sources ( struct i2c_client * client )
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2009-04-02 18:26:22 +04:00
u32 in = state - > route_in ;
2006-03-19 18:35:57 +03:00
msp34xxg_set_source ( client , 0x0008 , ( in > > 4 ) & 0xf ) ;
/* quasi-peak detector is set to same input as the loudspeaker (MAIN) */
msp34xxg_set_source ( client , 0x000c , ( in > > 4 ) & 0xf ) ;
msp34xxg_set_source ( client , 0x0009 , ( in > > 8 ) & 0xf ) ;
msp34xxg_set_source ( client , 0x000a , ( in > > 12 ) & 0xf ) ;
2006-03-31 02:50:34 +04:00
if ( state - > has_scart2_out )
2006-03-19 18:35:57 +03:00
msp34xxg_set_source ( client , 0x0041 , ( in > > 16 ) & 0xf ) ;
msp34xxg_set_source ( client , 0x000b , ( in > > 20 ) & 0xf ) ;
}
2006-03-19 14:21:56 +03:00
/* (re-)initialize the msp34xxg */
static void msp34xxg_reset ( struct i2c_client * client )
2006-01-09 20:32:40 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2009-04-02 18:26:22 +04:00
int tuner = ( state - > route_in > > 3 ) & 1 ;
2006-03-19 14:21:56 +03:00
int modus ;
2006-01-09 20:32:40 +03:00
2006-03-19 14:21:56 +03:00
/* initialize std to 1 (autodetect) to signal that no standard is
selected yet . */
state - > std = 1 ;
msp_reset ( client ) ;
2006-01-09 20:32:40 +03:00
2006-01-09 23:21:37 +03:00
if ( state - > has_i2s_conf )
msp_write_dem ( client , 0x40 , state - > i2s_mode ) ;
2006-01-09 20:32:40 +03:00
/* step-by-step initialisation, as described in the manual */
2006-03-19 13:25:42 +03:00
modus = msp34xxg_modus ( client ) ;
2006-03-19 18:35:57 +03:00
modus | = tuner ? 0x100 : 0 ;
2006-03-19 14:21:56 +03:00
msp_write_dem ( client , 0x30 , modus ) ;
2006-01-09 20:32:40 +03:00
/* write the dsps that may have an influence on
standard / audio autodetection right now */
2006-03-19 18:35:57 +03:00
msp34xxg_set_sources ( client ) ;
2006-01-09 20:32:40 +03:00
2006-03-19 14:21:56 +03:00
msp_write_dsp ( client , 0x0d , 0x1900 ) ; /* scart */
msp_write_dsp ( client , 0x0e , 0x3000 ) ; /* FM */
if ( state - > has_nicam )
msp_write_dsp ( client , 0x10 , 0x5a00 ) ; /* nicam */
2006-01-09 20:32:40 +03:00
2006-03-19 14:21:56 +03:00
/* set identification threshold. Personally, I
* I set it to a higher value than the default
* of 0x190 to ignore noisy stereo signals .
* this needs tuning . ( recommended range 0x00a0 - 0x03c0 )
* 0x7f0 = forced mono mode
*
* a2 threshold for stereo / bilingual .
* Note : this register is part of the Manual / Compatibility mode .
* It is supported by all ' G ' - family chips .
*/
msp_write_dem ( client , 0x22 , msp_stereo_thresh ) ;
2006-01-09 20:32:40 +03:00
}
int msp34xxg_thread ( void * data )
{
struct i2c_client * client = data ;
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-03-19 14:21:56 +03:00
int val , i ;
2006-01-09 20:32:40 +03:00
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " msp34xxg daemon started \n " ) ;
2011-10-04 16:44:02 +04:00
state - > detected_std = V4L2_STD_ALL ;
2007-07-17 15:03:35 +04:00
set_freezable ( ) ;
2006-01-09 20:32:40 +03:00
for ( ; ; ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " msp34xxg thread: sleep \n " ) ;
2006-01-09 20:32:40 +03:00
msp_sleep ( state , - 1 ) ;
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug , " msp34xxg thread: wakeup \n " ) ;
2006-01-09 20:32:40 +03:00
2007-12-12 14:25:18 +03:00
restart :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " thread: restart scan \n " ) ;
2006-01-09 20:32:40 +03:00
state - > restart = 0 ;
if ( kthread_should_stop ( ) )
break ;
2006-04-02 15:21:02 +04:00
if ( state - > mode = = MSP_MODE_EXTERN ) {
/* no carrier scan needed, just unmute */
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" thread: no carrier scan \n " ) ;
2006-04-02 15:21:02 +04:00
state - > scan_in_progress = 0 ;
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-04-02 15:21:02 +04:00
continue ;
}
2006-01-09 20:32:40 +03:00
/* setup the chip*/
msp34xxg_reset ( client ) ;
2006-10-02 00:56:32 +04:00
state - > std = state - > radio ? 0x40 :
( state - > force_btsc & & msp_standard = = 1 ) ? 32 : msp_standard ;
2006-03-19 14:21:56 +03:00
msp_write_dem ( client , 0x20 , state - > std ) ;
2006-10-02 00:56:32 +04:00
/* start autodetect */
2006-08-08 16:10:15 +04:00
if ( state - > std ! = 1 )
goto unmute ;
2006-01-09 20:32:40 +03:00
/* watch autodetect */
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" started autodetect, waiting for result \n " ) ;
2006-01-09 20:32:40 +03:00
for ( i = 0 ; i < 10 ; i + + ) {
if ( msp_sleep ( state , 100 ) )
goto restart ;
/* check results */
val = msp_read_dem ( client , 0x7e ) ;
if ( val < 0x07ff ) {
2006-03-19 14:21:56 +03:00
state - > std = val ;
2006-01-09 20:32:40 +03:00
break ;
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 2 , msp_debug ,
2007-12-12 14:25:18 +03:00
" detection still in progress \n " ) ;
2006-01-09 20:32:40 +03:00
}
2006-03-19 14:21:56 +03:00
if ( state - > std = = 1 ) {
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" detection still in progress after 10 tries. giving up. \n " ) ;
2006-01-09 20:32:40 +03:00
continue ;
}
2007-12-12 14:25:18 +03:00
unmute :
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" detected standard: %s (0x%04x) \n " ,
2006-03-19 14:21:56 +03:00
msp_standard_std_name ( state - > std ) , state - > std ) ;
2011-10-04 16:44:02 +04:00
state - > detected_std = msp_standard_std ( state - > std ) ;
2006-01-09 20:32:40 +03:00
2006-04-02 15:21:02 +04:00
if ( state - > std = = 9 ) {
/* AM NICAM mode */
msp_write_dsp ( client , 0x0e , 0x7c00 ) ;
}
2006-01-09 20:32:40 +03:00
/* unmute: dispatch sound to scart output, set scart volume */
2010-05-24 17:01:58 +04:00
msp_update_volume ( state ) ;
2006-01-09 20:32:40 +03:00
/* restore ACB */
if ( msp_write_dsp ( client , 0x13 , state - > acb ) )
return - 1 ;
2006-03-19 14:21:56 +03:00
/* the periodic stereo/SAP check is only relevant for
the 0x20 standard ( BTSC ) */
if ( state - > std ! = 0x20 )
continue ;
state - > watch_stereo = 1 ;
/* monitor tv audio mode, the first time don't wait
in order to get a quick stereo / SAP update */
watch_stereo ( client ) ;
while ( state - > watch_stereo ) {
watch_stereo ( client ) ;
if ( msp_sleep ( state , 5000 ) )
goto restart ;
}
2006-01-09 20:32:40 +03:00
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug , " thread: exit \n " ) ;
2006-01-09 20:32:40 +03:00
return 0 ;
}
2006-03-19 14:21:56 +03:00
static int msp34xxg_detect_stereo ( struct i2c_client * client )
2006-01-09 20:32:40 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-09 20:32:40 +03:00
int status = msp_read_dem ( client , 0x0200 ) ;
int is_bilingual = status & 0x100 ;
int is_stereo = status & 0x40 ;
2006-03-19 14:21:56 +03:00
int oldrx = state - > rxsubchans ;
2006-01-09 20:32:40 +03:00
2006-12-18 19:18:28 +03:00
if ( state - > mode = = MSP_MODE_EXTERN )
return 0 ;
2006-01-09 20:32:40 +03:00
state - > rxsubchans = 0 ;
if ( is_stereo )
2006-01-23 22:11:09 +03:00
state - > rxsubchans = V4L2_TUNER_SUB_STEREO ;
2006-01-09 20:32:40 +03:00
else
2006-01-23 22:11:09 +03:00
state - > rxsubchans = V4L2_TUNER_SUB_MONO ;
2006-01-09 20:32:40 +03:00
if ( is_bilingual ) {
2006-03-19 14:21:56 +03:00
if ( state - > std = = 0x20 )
state - > rxsubchans | = V4L2_TUNER_SUB_SAP ;
else
2007-12-12 14:25:18 +03:00
state - > rxsubchans =
V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2 ;
2006-01-09 20:32:40 +03:00
}
2016-11-16 14:10:14 +03:00
dev_dbg_lvl ( & client - > dev , 1 , msp_debug ,
2007-12-12 14:25:18 +03:00
" status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d \n " ,
2006-01-09 20:32:40 +03:00
status , is_stereo , is_bilingual , state - > rxsubchans ) ;
2006-03-19 14:21:56 +03:00
return ( oldrx ! = state - > rxsubchans ) ;
2006-01-09 20:32:40 +03:00
}
2006-03-08 16:50:07 +03:00
static void msp34xxg_set_audmode ( struct i2c_client * client )
2006-01-09 20:32:40 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-09 20:32:40 +03:00
2006-03-19 14:21:56 +03:00
if ( state - > std = = 0x20 ) {
if ( ( state - > rxsubchans & V4L2_TUNER_SUB_SAP ) & &
2006-03-29 23:29:00 +04:00
( state - > audmode = = V4L2_TUNER_MODE_LANG1_LANG2 | |
2006-03-19 14:21:56 +03:00
state - > audmode = = V4L2_TUNER_MODE_LANG2 ) ) {
msp_write_dem ( client , 0x20 , 0x21 ) ;
} else {
msp_write_dem ( client , 0x20 , 0x20 ) ;
}
}
2006-03-19 18:35:57 +03:00
msp34xxg_set_sources ( client ) ;
2006-01-09 20:32:40 +03:00
}
2006-01-23 22:11:09 +03:00
void msp_set_audmode ( struct i2c_client * client )
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-23 22:11:09 +03:00
switch ( state - > opmode ) {
case OPMODE_MANUAL :
case OPMODE_AUTODETECT :
msp3400c_set_audmode ( client ) ;
break ;
case OPMODE_AUTOSELECT :
msp34xxg_set_audmode ( client ) ;
break ;
}
}
2006-03-19 14:21:56 +03:00
int msp_detect_stereo ( struct i2c_client * client )
2006-01-23 22:11:09 +03:00
{
2008-11-25 00:16:46 +03:00
struct msp_state * state = to_state ( i2c_get_clientdata ( client ) ) ;
2006-01-23 22:11:09 +03:00
switch ( state - > opmode ) {
case OPMODE_MANUAL :
case OPMODE_AUTODETECT :
2006-03-19 14:21:56 +03:00
return msp3400c_detect_stereo ( client ) ;
2006-01-23 22:11:09 +03:00
case OPMODE_AUTOSELECT :
2006-03-19 14:21:56 +03:00
return msp34xxg_detect_stereo ( client ) ;
2006-01-23 22:11:09 +03:00
}
2006-03-19 14:21:56 +03:00
return 0 ;
2006-01-23 22:11:09 +03:00
}