2011-04-07 23:27:43 +04:00
/*
* Sony CXD2820R demodulator driver
*
* Copyright ( C ) 2010 Antti Palosaari < crope @ iki . fi >
*
* 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 . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
2011-05-03 01:19:13 +04:00
# include "cxd2820r_priv.h"
2011-12-31 05:22:10 +04:00
int cxd2820r_set_frontend_c ( struct dvb_frontend * fe )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
int ret , i ;
u8 buf [ 2 ] ;
2011-11-13 21:41:25 +04:00
u32 if_freq ;
2011-04-07 23:27:43 +04:00
u16 if_ctl ;
u64 num ;
struct reg_val_mask tab [ ] = {
{ 0x00080 , 0x01 , 0xff } ,
{ 0x00081 , 0x05 , 0xff } ,
{ 0x00085 , 0x07 , 0xff } ,
{ 0x00088 , 0x01 , 0xff } ,
{ 0x00082 , 0x20 , 0x60 } ,
{ 0x1016a , 0x48 , 0xff } ,
{ 0x100a5 , 0x00 , 0x01 } ,
{ 0x10020 , 0x06 , 0x07 } ,
{ 0x10059 , 0x50 , 0xff } ,
{ 0x10087 , 0x0c , 0x3c } ,
{ 0x1008b , 0x07 , 0xff } ,
{ 0x1001f , priv - > cfg . if_agc_polarity < < 7 , 0x80 } ,
{ 0x10070 , priv - > cfg . ts_mode , 0xff } ,
2014-06-03 21:19:07 +04:00
{ 0x10071 , ! priv - > cfg . ts_clock_inv < < 4 , 0x10 } ,
2011-04-07 23:27:43 +04:00
} ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: frequency=%d symbol_rate=%d \n " , __func__ ,
c - > frequency , c - > symbol_rate ) ;
2011-04-07 23:27:43 +04:00
/* program tuner */
if ( fe - > ops . tuner_ops . set_params )
2011-12-24 19:24:33 +04:00
fe - > ops . tuner_ops . set_params ( fe ) ;
2011-04-07 23:27:43 +04:00
2011-12-23 01:11:39 +04:00
if ( priv - > delivery_system ! = SYS_DVBC_ANNEX_A ) {
2011-04-07 23:27:43 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( tab ) ; i + + ) {
ret = cxd2820r_wr_reg_mask ( priv , tab [ i ] . reg ,
tab [ i ] . val , tab [ i ] . mask ) ;
if ( ret )
goto error ;
}
}
2011-12-23 01:11:39 +04:00
priv - > delivery_system = SYS_DVBC_ANNEX_A ;
2014-09-03 22:22:02 +04:00
priv - > ber_running = false ; /* tune stops BER counter */
2011-04-07 23:27:43 +04:00
2011-11-13 21:41:25 +04:00
/* program IF frequency */
if ( fe - > ops . tuner_ops . get_if_frequency ) {
ret = fe - > ops . tuner_ops . get_if_frequency ( fe , & if_freq ) ;
if ( ret )
goto error ;
} else
if_freq = 0 ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: if_freq=%d \n " , __func__ , if_freq ) ;
2011-11-13 21:41:25 +04:00
num = if_freq / 1000 ; /* Hz => kHz */
2011-04-07 23:27:43 +04:00
num * = 0x4000 ;
2015-04-16 22:43:54 +03:00
if_ctl = 0x4000 - DIV_ROUND_CLOSEST_ULL ( num , 41000 ) ;
2011-04-07 23:27:43 +04:00
buf [ 0 ] = ( if_ctl > > 8 ) & 0x3f ;
buf [ 1 ] = ( if_ctl > > 0 ) & 0xff ;
ret = cxd2820r_wr_regs ( priv , 0x10042 , buf , 2 ) ;
if ( ret )
goto error ;
ret = cxd2820r_wr_reg ( priv , 0x000ff , 0x08 ) ;
if ( ret )
goto error ;
ret = cxd2820r_wr_reg ( priv , 0x000fe , 0x01 ) ;
if ( ret )
goto error ;
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-12-31 05:22:10 +04:00
int cxd2820r_get_frontend_c ( struct dvb_frontend * fe )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
int ret ;
u8 buf [ 2 ] ;
ret = cxd2820r_rd_regs ( priv , 0x1001a , buf , 2 ) ;
if ( ret )
goto error ;
c - > symbol_rate = 2500 * ( ( buf [ 0 ] & 0x0f ) < < 8 | buf [ 1 ] ) ;
ret = cxd2820r_rd_reg ( priv , 0x10019 , & buf [ 0 ] ) ;
if ( ret )
goto error ;
2012-05-30 12:28:46 +04:00
switch ( ( buf [ 0 ] > > 0 ) & 0x07 ) {
2011-04-07 23:27:43 +04:00
case 0 :
c - > modulation = QAM_16 ;
break ;
case 1 :
c - > modulation = QAM_32 ;
break ;
case 2 :
c - > modulation = QAM_64 ;
break ;
case 3 :
c - > modulation = QAM_128 ;
break ;
case 4 :
c - > modulation = QAM_256 ;
break ;
}
switch ( ( buf [ 0 ] > > 7 ) & 0x01 ) {
case 0 :
c - > inversion = INVERSION_OFF ;
break ;
case 1 :
c - > inversion = INVERSION_ON ;
break ;
}
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_read_ber_c ( struct dvb_frontend * fe , u32 * ber )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret ;
u8 buf [ 3 ] , start_ber = 0 ;
* ber = 0 ;
if ( priv - > ber_running ) {
ret = cxd2820r_rd_regs ( priv , 0x10076 , buf , sizeof ( buf ) ) ;
if ( ret )
goto error ;
if ( ( buf [ 2 ] > > 7 ) & 0x01 | | ( buf [ 2 ] > > 4 ) & 0x01 ) {
* ber = ( buf [ 2 ] & 0x0f ) < < 16 | buf [ 1 ] < < 8 | buf [ 0 ] ;
start_ber = 1 ;
}
} else {
2014-09-03 22:22:02 +04:00
priv - > ber_running = true ;
2011-04-07 23:27:43 +04:00
start_ber = 1 ;
}
if ( start_ber ) {
/* (re)start BER */
ret = cxd2820r_wr_reg ( priv , 0x10079 , 0x01 ) ;
if ( ret )
goto error ;
}
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_read_signal_strength_c ( struct dvb_frontend * fe ,
2011-04-07 23:27:43 +04:00
u16 * strength )
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret ;
u8 buf [ 2 ] ;
u16 tmp ;
ret = cxd2820r_rd_regs ( priv , 0x10049 , buf , sizeof ( buf ) ) ;
if ( ret )
goto error ;
tmp = ( buf [ 0 ] & 0x03 ) < < 8 | buf [ 1 ] ;
tmp = ( ~ tmp & 0x03ff ) ;
if ( tmp = = 512 )
/* ~no signal */
tmp = 0 ;
else if ( tmp > 350 )
tmp = 350 ;
/* scale value to 0x0000-0xffff */
* strength = tmp * 0xffff / ( 350 - 0 ) ;
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_read_snr_c ( struct dvb_frontend * fe , u16 * snr )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret ;
u8 tmp ;
unsigned int A , B ;
/* report SNR in dB * 10 */
ret = cxd2820r_rd_reg ( priv , 0x10019 , & tmp ) ;
if ( ret )
goto error ;
if ( ( ( tmp > > 0 ) & 0x03 ) % 2 ) {
A = 875 ;
B = 650 ;
} else {
A = 950 ;
B = 760 ;
}
ret = cxd2820r_rd_reg ( priv , 0x1004d , & tmp ) ;
if ( ret )
goto error ;
# define CXD2820R_LOG2_E_24 24204406 /* log2(e) << 24 */
if ( tmp )
* snr = A * ( intlog2 ( B / tmp ) > > 5 ) / ( CXD2820R_LOG2_E_24 > > 5 )
/ 10 ;
else
* snr = 0 ;
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_read_ucblocks_c ( struct dvb_frontend * fe , u32 * ucblocks )
2011-04-07 23:27:43 +04:00
{
* ucblocks = 0 ;
/* no way to read ? */
return 0 ;
}
2015-06-07 20:53:52 +03:00
int cxd2820r_read_status_c ( struct dvb_frontend * fe , enum fe_status * status )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret ;
u8 buf [ 2 ] ;
* status = 0 ;
ret = cxd2820r_rd_regs ( priv , 0x10088 , buf , sizeof ( buf ) ) ;
if ( ret )
goto error ;
if ( ( ( buf [ 0 ] > > 0 ) & 0x01 ) = = 1 ) {
* status | = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC ;
if ( ( ( buf [ 1 ] > > 3 ) & 0x01 ) = = 1 ) {
* status | = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK ;
}
}
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: lock=%02x %02x \n " , __func__ , buf [ 0 ] ,
buf [ 1 ] ) ;
2011-04-07 23:27:43 +04:00
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_init_c ( struct dvb_frontend * fe )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret ;
ret = cxd2820r_wr_reg ( priv , 0x00085 , 0x07 ) ;
if ( ret )
goto error ;
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_sleep_c ( struct dvb_frontend * fe )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret , i ;
struct reg_val_mask tab [ ] = {
{ 0x000ff , 0x1f , 0xff } ,
{ 0x00085 , 0x00 , 0xff } ,
{ 0x00088 , 0x01 , 0xff } ,
{ 0x00081 , 0x00 , 0xff } ,
{ 0x00080 , 0x00 , 0xff } ,
} ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s \n " , __func__ ) ;
2011-04-07 23:27:43 +04:00
priv - > delivery_system = SYS_UNDEFINED ;
for ( i = 0 ; i < ARRAY_SIZE ( tab ) ; i + + ) {
ret = cxd2820r_wr_reg_mask ( priv , tab [ i ] . reg , tab [ i ] . val ,
tab [ i ] . mask ) ;
if ( ret )
goto error ;
}
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
2011-05-03 01:19:13 +04:00
int cxd2820r_get_tune_settings_c ( struct dvb_frontend * fe ,
2011-04-07 23:27:43 +04:00
struct dvb_frontend_tune_settings * s )
{
s - > min_delay_ms = 500 ;
s - > step_size = 0 ; /* no zigzag */
s - > max_drift = 0 ;
return 0 ;
}