2012-03-08 01:11:03 +04:00
/*
Driver for M88RS2000 demodulator and tuner
Copyright ( C ) 2012 Malcolm Priestley ( tvboxspy @ gmail . com )
Beta Driver
Include various calculation code from DS3000 driver .
Copyright ( C ) 2009 Konstantin Dimitrov .
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 <linux/init.h>
# include <linux/module.h>
# include <linux/device.h>
# include <linux/jiffies.h>
# include <linux/string.h>
# include <linux/slab.h>
# include <linux/types.h>
# include "dvb_frontend.h"
# include "m88rs2000.h"
struct m88rs2000_state {
struct i2c_adapter * i2c ;
const struct m88rs2000_config * config ;
struct dvb_frontend frontend ;
u8 no_lock_count ;
u32 tuner_frequency ;
u32 symbol_rate ;
2015-06-07 20:53:52 +03:00
enum fe_code_rate fec_inner ;
2012-03-08 01:11:03 +04:00
u8 tuner_level ;
int errmode ;
} ;
static int m88rs2000_debug ;
module_param_named ( debug , m88rs2000_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " set debugging level (1=info (or-able)). " ) ;
# define dprintk(level, args...) do { \
if ( level & m88rs2000_debug ) \
printk ( KERN_DEBUG " m88rs2000-fe: " args ) ; \
} while ( 0 )
# define deb_info(args...) dprintk(0x01, args)
# define info(format, arg...) \
printk ( KERN_INFO " m88rs2000-fe: " format " \n " , # # arg )
2012-12-29 02:40:33 +04:00
static int m88rs2000_writereg ( struct m88rs2000_state * state ,
2012-03-08 01:11:03 +04:00
u8 reg , u8 data )
{
int ret ;
u8 buf [ ] = { reg , data } ;
struct i2c_msg msg = {
2012-12-29 02:40:33 +04:00
. addr = state - > config - > demod_addr ,
2012-03-08 01:11:03 +04:00
. flags = 0 ,
. buf = buf ,
. len = 2
} ;
ret = i2c_transfer ( state - > i2c , & msg , 1 ) ;
if ( ret ! = 1 )
deb_info ( " %s: writereg error (reg == 0x%02x, val == 0x%02x, "
" ret == %i) \n " , __func__ , reg , data , ret ) ;
return ( ret ! = 1 ) ? - EREMOTEIO : 0 ;
}
2012-12-29 02:40:33 +04:00
static u8 m88rs2000_readreg ( struct m88rs2000_state * state , u8 reg )
2012-03-08 01:11:03 +04:00
{
int ret ;
u8 b0 [ ] = { reg } ;
u8 b1 [ ] = { 0 } ;
2012-12-29 02:40:33 +04:00
2012-03-08 01:11:03 +04:00
struct i2c_msg msg [ ] = {
{
2012-12-29 02:40:33 +04:00
. addr = state - > config - > demod_addr ,
2012-03-08 01:11:03 +04:00
. flags = 0 ,
. buf = b0 ,
. len = 1
} , {
2012-12-29 02:40:33 +04:00
. addr = state - > config - > demod_addr ,
2012-03-08 01:11:03 +04:00
. flags = I2C_M_RD ,
. buf = b1 ,
. len = 1
}
} ;
ret = i2c_transfer ( state - > i2c , msg , 2 ) ;
if ( ret ! = 2 )
deb_info ( " %s: readreg error (reg == 0x%02x, ret == %i) \n " ,
__func__ , reg , ret ) ;
return b1 [ 0 ] ;
}
2013-12-24 20:17:12 +04:00
static u32 m88rs2000_get_mclk ( struct dvb_frontend * fe )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
u32 mclk ;
u8 reg ;
/* Must not be 0x00 or 0xff */
reg = m88rs2000_readreg ( state , 0x86 ) ;
if ( ! reg | | reg = = 0xff )
return 0 ;
reg / = 2 ;
reg + = 1 ;
mclk = ( u32 ) ( reg * RS2000_FE_CRYSTAL_KHZ + 28 / 2 ) / 28 ;
return mclk ;
}
static int m88rs2000_set_carrieroffset ( struct dvb_frontend * fe , s16 offset )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
u32 mclk ;
s32 tmp ;
u8 reg ;
int ret ;
mclk = m88rs2000_get_mclk ( fe ) ;
if ( ! mclk )
return - EINVAL ;
tmp = ( offset * 4096 + ( s32 ) mclk / 2 ) / ( s32 ) mclk ;
if ( tmp < 0 )
tmp + = 4096 ;
/* Carrier Offset */
ret = m88rs2000_writereg ( state , 0x9c , ( u8 ) ( tmp > > 4 ) ) ;
reg = m88rs2000_readreg ( state , 0x9d ) ;
reg & = 0xf ;
reg | = ( u8 ) ( tmp & 0xf ) < < 4 ;
ret | = m88rs2000_writereg ( state , 0x9d , reg ) ;
return ret ;
}
2012-03-08 01:11:03 +04:00
static int m88rs2000_set_symbolrate ( struct dvb_frontend * fe , u32 srate )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
int ret ;
2013-12-24 20:18:46 +04:00
u64 temp ;
u32 mclk ;
2012-03-08 01:11:03 +04:00
u8 b [ 3 ] ;
if ( ( srate < 1000000 ) | | ( srate > 45000000 ) )
return - EINVAL ;
2013-12-24 20:18:46 +04:00
mclk = m88rs2000_get_mclk ( fe ) ;
if ( ! mclk )
return - EINVAL ;
2012-03-08 01:11:03 +04:00
temp = srate / 1000 ;
2013-12-24 20:18:46 +04:00
temp * = 1 < < 24 ;
do_div ( temp , mclk ) ;
2012-03-08 01:11:03 +04:00
b [ 0 ] = ( u8 ) ( temp > > 16 ) & 0xff ;
b [ 1 ] = ( u8 ) ( temp > > 8 ) & 0xff ;
b [ 2 ] = ( u8 ) temp & 0xff ;
2013-12-24 20:18:46 +04:00
2012-12-29 02:40:33 +04:00
ret = m88rs2000_writereg ( state , 0x93 , b [ 2 ] ) ;
ret | = m88rs2000_writereg ( state , 0x94 , b [ 1 ] ) ;
ret | = m88rs2000_writereg ( state , 0x95 , b [ 0 ] ) ;
2012-03-08 01:11:03 +04:00
2013-12-24 20:18:46 +04:00
if ( srate > 10000000 )
ret | = m88rs2000_writereg ( state , 0xa0 , 0x20 ) ;
else
ret | = m88rs2000_writereg ( state , 0xa0 , 0x60 ) ;
ret | = m88rs2000_writereg ( state , 0xa1 , 0xe0 ) ;
if ( srate > 12000000 )
ret | = m88rs2000_writereg ( state , 0xa3 , 0x20 ) ;
else if ( srate > 2800000 )
ret | = m88rs2000_writereg ( state , 0xa3 , 0x98 ) ;
else
ret | = m88rs2000_writereg ( state , 0xa3 , 0x90 ) ;
2012-03-08 01:11:03 +04:00
deb_info ( " m88rs2000: m88rs2000_set_symbolrate \n " ) ;
return ret ;
}
static int m88rs2000_send_diseqc_msg ( struct dvb_frontend * fe ,
struct dvb_diseqc_master_cmd * m )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
int i ;
u8 reg ;
deb_info ( " %s \n " , __func__ ) ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x9a , 0x30 ) ;
reg = m88rs2000_readreg ( state , 0xb2 ) ;
2012-03-08 01:11:03 +04:00
reg & = 0x3f ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb2 , reg ) ;
2012-03-08 01:11:03 +04:00
for ( i = 0 ; i < m - > msg_len ; i + + )
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb3 + i , m - > msg [ i ] ) ;
2012-03-08 01:11:03 +04:00
2012-12-29 02:40:33 +04:00
reg = m88rs2000_readreg ( state , 0xb1 ) ;
2012-03-08 01:11:03 +04:00
reg & = 0x87 ;
reg | = ( ( m - > msg_len - 1 ) < < 3 ) | 0x07 ;
reg & = 0x7f ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb1 , reg ) ;
2012-03-08 01:11:03 +04:00
for ( i = 0 ; i < 15 ; i + + ) {
2012-12-29 02:40:33 +04:00
if ( ( m88rs2000_readreg ( state , 0xb1 ) & 0x40 ) = = 0x0 )
2012-03-08 01:11:03 +04:00
break ;
msleep ( 20 ) ;
}
2012-12-29 02:40:33 +04:00
reg = m88rs2000_readreg ( state , 0xb1 ) ;
2012-03-08 01:11:03 +04:00
if ( ( reg & 0x40 ) > 0x0 ) {
reg & = 0x7f ;
reg | = 0x40 ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb1 , reg ) ;
2012-03-08 01:11:03 +04:00
}
2012-12-29 02:40:33 +04:00
reg = m88rs2000_readreg ( state , 0xb2 ) ;
2012-03-08 01:11:03 +04:00
reg & = 0x3f ;
reg | = 0x80 ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb2 , reg ) ;
m88rs2000_writereg ( state , 0x9a , 0xb0 ) ;
2012-03-08 01:11:03 +04:00
return 0 ;
}
static int m88rs2000_send_diseqc_burst ( struct dvb_frontend * fe ,
2015-06-07 20:53:52 +03:00
enum fe_sec_mini_cmd burst )
2012-03-08 01:11:03 +04:00
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
u8 reg0 , reg1 ;
deb_info ( " %s \n " , __func__ ) ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x9a , 0x30 ) ;
2012-03-08 01:11:03 +04:00
msleep ( 50 ) ;
2012-12-29 02:40:33 +04:00
reg0 = m88rs2000_readreg ( state , 0xb1 ) ;
reg1 = m88rs2000_readreg ( state , 0xb2 ) ;
2012-03-14 23:31:26 +04:00
/* TODO complete this section */
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb2 , reg1 ) ;
m88rs2000_writereg ( state , 0xb1 , reg0 ) ;
m88rs2000_writereg ( state , 0x9a , 0xb0 ) ;
2012-03-08 01:11:03 +04:00
return 0 ;
}
2015-06-07 20:53:52 +03:00
static int m88rs2000_set_tone ( struct dvb_frontend * fe ,
enum fe_sec_tone_mode tone )
2012-03-08 01:11:03 +04:00
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
u8 reg0 , reg1 ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x9a , 0x30 ) ;
reg0 = m88rs2000_readreg ( state , 0xb1 ) ;
reg1 = m88rs2000_readreg ( state , 0xb2 ) ;
2012-03-08 01:11:03 +04:00
reg1 & = 0x3f ;
switch ( tone ) {
case SEC_TONE_ON :
reg0 | = 0x4 ;
reg0 & = 0xbc ;
2012-03-14 23:31:26 +04:00
break ;
2012-03-08 01:11:03 +04:00
case SEC_TONE_OFF :
reg1 | = 0x80 ;
2012-03-14 23:31:26 +04:00
break ;
2012-03-08 01:11:03 +04:00
default :
2012-03-14 23:31:26 +04:00
break ;
2012-03-08 01:11:03 +04:00
}
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb2 , reg1 ) ;
m88rs2000_writereg ( state , 0xb1 , reg0 ) ;
m88rs2000_writereg ( state , 0x9a , 0xb0 ) ;
2012-03-08 01:11:03 +04:00
return 0 ;
}
struct inittab {
u8 cmd ;
u8 reg ;
u8 val ;
} ;
2014-03-25 05:31:58 +04:00
static struct inittab m88rs2000_setup [ ] = {
2012-03-08 01:11:03 +04:00
{ DEMOD_WRITE , 0x9a , 0x30 } ,
{ DEMOD_WRITE , 0x00 , 0x01 } ,
{ WRITE_DELAY , 0x19 , 0x00 } ,
{ DEMOD_WRITE , 0x00 , 0x00 } ,
{ DEMOD_WRITE , 0x9a , 0xb0 } ,
{ DEMOD_WRITE , 0x81 , 0xc1 } ,
{ DEMOD_WRITE , 0x81 , 0x81 } ,
{ DEMOD_WRITE , 0x86 , 0xc6 } ,
{ DEMOD_WRITE , 0x9a , 0x30 } ,
{ DEMOD_WRITE , 0xf0 , 0x22 } ,
{ DEMOD_WRITE , 0xf1 , 0xbf } ,
{ DEMOD_WRITE , 0xb0 , 0x45 } ,
2012-03-14 23:31:26 +04:00
{ DEMOD_WRITE , 0xb2 , 0x01 } , /* set voltage pin always set 1*/
2012-03-08 01:11:03 +04:00
{ DEMOD_WRITE , 0x9a , 0xb0 } ,
{ 0xff , 0xaa , 0xff }
} ;
2014-03-25 05:31:58 +04:00
static struct inittab m88rs2000_shutdown [ ] = {
2012-03-08 01:11:03 +04:00
{ DEMOD_WRITE , 0x9a , 0x30 } ,
{ DEMOD_WRITE , 0xb0 , 0x00 } ,
{ DEMOD_WRITE , 0xf1 , 0x89 } ,
{ DEMOD_WRITE , 0x00 , 0x01 } ,
{ DEMOD_WRITE , 0x9a , 0xb0 } ,
{ DEMOD_WRITE , 0x81 , 0x81 } ,
{ 0xff , 0xaa , 0xff }
} ;
2014-03-25 05:31:58 +04:00
static struct inittab fe_reset [ ] = {
2012-03-08 01:11:03 +04:00
{ DEMOD_WRITE , 0x00 , 0x01 } ,
{ DEMOD_WRITE , 0x20 , 0x81 } ,
{ DEMOD_WRITE , 0x21 , 0x80 } ,
{ DEMOD_WRITE , 0x10 , 0x33 } ,
{ DEMOD_WRITE , 0x11 , 0x44 } ,
{ DEMOD_WRITE , 0x12 , 0x07 } ,
{ DEMOD_WRITE , 0x18 , 0x20 } ,
{ DEMOD_WRITE , 0x28 , 0x04 } ,
{ DEMOD_WRITE , 0x29 , 0x8e } ,
{ DEMOD_WRITE , 0x3b , 0xff } ,
{ DEMOD_WRITE , 0x32 , 0x10 } ,
{ DEMOD_WRITE , 0x33 , 0x02 } ,
{ DEMOD_WRITE , 0x34 , 0x30 } ,
{ DEMOD_WRITE , 0x35 , 0xff } ,
{ DEMOD_WRITE , 0x38 , 0x50 } ,
{ DEMOD_WRITE , 0x39 , 0x68 } ,
{ DEMOD_WRITE , 0x3c , 0x7f } ,
{ DEMOD_WRITE , 0x3d , 0x0f } ,
{ DEMOD_WRITE , 0x45 , 0x20 } ,
{ DEMOD_WRITE , 0x46 , 0x24 } ,
{ DEMOD_WRITE , 0x47 , 0x7c } ,
{ DEMOD_WRITE , 0x48 , 0x16 } ,
{ DEMOD_WRITE , 0x49 , 0x04 } ,
{ DEMOD_WRITE , 0x4a , 0x01 } ,
{ DEMOD_WRITE , 0x4b , 0x78 } ,
{ DEMOD_WRITE , 0 X4d , 0xd2 } ,
{ DEMOD_WRITE , 0x4e , 0x6d } ,
{ DEMOD_WRITE , 0x50 , 0x30 } ,
{ DEMOD_WRITE , 0x51 , 0x30 } ,
{ DEMOD_WRITE , 0x54 , 0x7b } ,
{ DEMOD_WRITE , 0x56 , 0x09 } ,
{ DEMOD_WRITE , 0x58 , 0x59 } ,
{ DEMOD_WRITE , 0x59 , 0x37 } ,
{ DEMOD_WRITE , 0x63 , 0xfa } ,
{ 0xff , 0xaa , 0xff }
} ;
2014-03-25 05:31:58 +04:00
static struct inittab fe_trigger [ ] = {
2012-03-08 01:11:03 +04:00
{ DEMOD_WRITE , 0x97 , 0x04 } ,
{ DEMOD_WRITE , 0x99 , 0x77 } ,
{ DEMOD_WRITE , 0x9b , 0x64 } ,
{ DEMOD_WRITE , 0x9e , 0x00 } ,
{ DEMOD_WRITE , 0x9f , 0xf8 } ,
{ DEMOD_WRITE , 0x98 , 0xff } ,
{ DEMOD_WRITE , 0xc0 , 0x0f } ,
{ DEMOD_WRITE , 0x89 , 0x01 } ,
{ DEMOD_WRITE , 0x00 , 0x00 } ,
{ WRITE_DELAY , 0x0a , 0x00 } ,
{ DEMOD_WRITE , 0x00 , 0x01 } ,
{ DEMOD_WRITE , 0x00 , 0x00 } ,
{ DEMOD_WRITE , 0x9a , 0xb0 } ,
{ 0xff , 0xaa , 0xff }
} ;
static int m88rs2000_tab_set ( struct m88rs2000_state * state ,
struct inittab * tab )
{
int ret = 0 ;
u8 i ;
if ( tab = = NULL )
return - EINVAL ;
for ( i = 0 ; i < 255 ; i + + ) {
switch ( tab [ i ] . cmd ) {
case 0x01 :
2012-12-29 02:40:33 +04:00
ret = m88rs2000_writereg ( state , tab [ i ] . reg ,
2012-03-08 01:11:03 +04:00
tab [ i ] . val ) ;
break ;
case 0x10 :
if ( tab [ i ] . reg > 0 )
mdelay ( tab [ i ] . reg ) ;
break ;
case 0xff :
if ( tab [ i ] . reg = = 0xaa & & tab [ i ] . val = = 0xff )
return 0 ;
case 0x00 :
break ;
default :
return - EINVAL ;
}
if ( ret < 0 )
return - ENODEV ;
}
return 0 ;
}
2015-06-07 20:53:52 +03:00
static int m88rs2000_set_voltage ( struct dvb_frontend * fe ,
enum fe_sec_voltage volt )
2012-03-08 01:11:03 +04:00
{
2012-05-08 11:25:24 +04:00
struct m88rs2000_state * state = fe - > demodulator_priv ;
u8 data ;
2012-12-29 02:40:33 +04:00
data = m88rs2000_readreg ( state , 0xb2 ) ;
2012-05-08 11:25:24 +04:00
data | = 0x03 ; /* bit0 V/H, bit1 off/on */
switch ( volt ) {
case SEC_VOLTAGE_18 :
data & = ~ 0x03 ;
break ;
case SEC_VOLTAGE_13 :
data & = ~ 0x03 ;
data | = 0x01 ;
break ;
case SEC_VOLTAGE_OFF :
break ;
}
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xb2 , data ) ;
2012-03-08 01:11:03 +04:00
return 0 ;
}
static int m88rs2000_init ( struct dvb_frontend * fe )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
int ret ;
deb_info ( " m88rs2000: init chip \n " ) ;
/* Setup frontend from shutdown/cold */
2012-05-08 11:08:04 +04:00
if ( state - > config - > inittab )
ret = m88rs2000_tab_set ( state ,
( struct inittab * ) state - > config - > inittab ) ;
else
ret = m88rs2000_tab_set ( state , m88rs2000_setup ) ;
2012-03-08 01:11:03 +04:00
return ret ;
}
static int m88rs2000_sleep ( struct dvb_frontend * fe )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
int ret ;
/* Shutdown the frondend */
ret = m88rs2000_tab_set ( state , m88rs2000_shutdown ) ;
return ret ;
}
2015-06-07 20:53:52 +03:00
static int m88rs2000_read_status ( struct dvb_frontend * fe ,
enum fe_status * status )
2012-03-08 01:11:03 +04:00
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
2012-12-29 02:40:33 +04:00
u8 reg = m88rs2000_readreg ( state , 0x8c ) ;
2012-03-08 01:11:03 +04:00
* status = 0 ;
2013-12-28 21:00:40 +04:00
if ( ( reg & 0xee ) = = 0xee ) {
2012-03-08 01:11:03 +04:00
* status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
2012-08-07 01:35:26 +04:00
| FE_HAS_SYNC | FE_HAS_LOCK ;
2012-03-08 01:11:03 +04:00
if ( state - > config - > set_ts_params )
state - > config - > set_ts_params ( fe , CALL_IS_READ ) ;
}
return 0 ;
}
static int m88rs2000_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
2012-12-29 02:40:16 +04:00
struct m88rs2000_state * state = fe - > demodulator_priv ;
u8 tmp0 , tmp1 ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x9a , 0x30 ) ;
tmp0 = m88rs2000_readreg ( state , 0xd8 ) ;
2012-12-29 02:40:16 +04:00
if ( ( tmp0 & 0x10 ) ! = 0 ) {
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x9a , 0xb0 ) ;
2012-12-29 02:40:16 +04:00
* ber = 0xffffffff ;
return 0 ;
}
2012-12-29 02:40:33 +04:00
* ber = ( m88rs2000_readreg ( state , 0xd7 ) < < 8 ) |
m88rs2000_readreg ( state , 0xd6 ) ;
2012-12-29 02:40:16 +04:00
2012-12-29 02:40:33 +04:00
tmp1 = m88rs2000_readreg ( state , 0xd9 ) ;
m88rs2000_writereg ( state , 0xd9 , ( tmp1 & ~ 7 ) | 4 ) ;
2012-12-29 02:40:16 +04:00
/* needs twice */
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xd8 , ( tmp0 & ~ 8 ) | 0x30 ) ;
m88rs2000_writereg ( state , 0xd8 , ( tmp0 & ~ 8 ) | 0x30 ) ;
m88rs2000_writereg ( state , 0x9a , 0xb0 ) ;
2012-12-29 02:40:16 +04:00
2012-03-08 01:11:03 +04:00
return 0 ;
}
static int m88rs2000_read_signal_strength ( struct dvb_frontend * fe ,
u16 * strength )
{
2013-01-06 15:40:42 +04:00
if ( fe - > ops . tuner_ops . get_rf_strength )
fe - > ops . tuner_ops . get_rf_strength ( fe , strength ) ;
2012-03-08 01:11:03 +04:00
return 0 ;
}
static int m88rs2000_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
2012-12-29 02:40:16 +04:00
struct m88rs2000_state * state = fe - > demodulator_priv ;
2012-12-29 02:40:33 +04:00
* snr = 512 * m88rs2000_readreg ( state , 0x65 ) ;
2012-12-29 02:40:16 +04:00
2012-03-08 01:11:03 +04:00
return 0 ;
}
static int m88rs2000_read_ucblocks ( struct dvb_frontend * fe , u32 * ucblocks )
{
2012-12-29 02:40:16 +04:00
struct m88rs2000_state * state = fe - > demodulator_priv ;
u8 tmp ;
2012-12-29 02:40:33 +04:00
* ucblocks = ( m88rs2000_readreg ( state , 0xd5 ) < < 8 ) |
m88rs2000_readreg ( state , 0xd4 ) ;
tmp = m88rs2000_readreg ( state , 0xd8 ) ;
m88rs2000_writereg ( state , 0xd8 , tmp & ~ 0x20 ) ;
2012-12-29 02:40:16 +04:00
/* needs two times */
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0xd8 , tmp | 0x20 ) ;
m88rs2000_writereg ( state , 0xd8 , tmp | 0x20 ) ;
2012-12-29 02:40:16 +04:00
2012-03-08 01:11:03 +04:00
return 0 ;
}
static int m88rs2000_set_fec ( struct m88rs2000_state * state ,
2015-06-07 20:53:52 +03:00
enum fe_code_rate fec )
2012-03-08 01:11:03 +04:00
{
2013-12-28 21:02:44 +04:00
u8 fec_set , reg ;
int ret ;
2012-03-08 01:11:03 +04:00
switch ( fec ) {
2013-12-28 21:02:44 +04:00
case FEC_1_2 :
fec_set = 0x8 ;
2012-03-08 01:11:03 +04:00
break ;
case FEC_2_3 :
2013-12-28 21:02:44 +04:00
fec_set = 0x10 ;
2012-03-08 01:11:03 +04:00
break ;
case FEC_3_4 :
2013-12-28 21:02:44 +04:00
fec_set = 0x20 ;
2012-03-08 01:11:03 +04:00
break ;
case FEC_5_6 :
2013-12-28 21:02:44 +04:00
fec_set = 0x40 ;
2012-03-08 01:11:03 +04:00
break ;
case FEC_7_8 :
2013-12-28 21:02:44 +04:00
fec_set = 0x80 ;
break ;
2012-03-08 01:11:03 +04:00
case FEC_AUTO :
default :
2013-12-28 21:02:44 +04:00
fec_set = 0x0 ;
2012-03-08 01:11:03 +04:00
}
2013-12-28 21:02:44 +04:00
reg = m88rs2000_readreg ( state , 0x70 ) ;
reg & = 0x7 ;
ret = m88rs2000_writereg ( state , 0x70 , reg | fec_set ) ;
2012-03-08 01:11:03 +04:00
2013-12-28 21:02:44 +04:00
ret | = m88rs2000_writereg ( state , 0x76 , 0x8 ) ;
return ret ;
}
2012-03-08 01:11:03 +04:00
2015-06-07 20:53:52 +03:00
static enum fe_code_rate m88rs2000_get_fec ( struct m88rs2000_state * state )
2012-03-08 01:11:03 +04:00
{
u8 reg ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x9a , 0x30 ) ;
reg = m88rs2000_readreg ( state , 0x76 ) ;
m88rs2000_writereg ( state , 0x9a , 0xb0 ) ;
2012-03-08 01:11:03 +04:00
2013-12-28 21:04:51 +04:00
reg & = 0xf0 ;
reg > > = 5 ;
2012-03-08 01:11:03 +04:00
switch ( reg ) {
2013-12-28 21:04:51 +04:00
case 0x4 :
2012-03-08 01:11:03 +04:00
return FEC_1_2 ;
2013-12-28 21:04:51 +04:00
case 0x3 :
2012-03-08 01:11:03 +04:00
return FEC_2_3 ;
2013-12-28 21:04:51 +04:00
case 0x2 :
2012-03-08 01:11:03 +04:00
return FEC_3_4 ;
2013-12-28 21:04:51 +04:00
case 0x1 :
2012-03-08 01:11:03 +04:00
return FEC_5_6 ;
2013-12-28 21:04:51 +04:00
case 0x0 :
2012-03-08 01:11:03 +04:00
return FEC_7_8 ;
default :
break ;
}
return FEC_AUTO ;
}
static int m88rs2000_set_frontend ( struct dvb_frontend * fe )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2015-06-07 20:53:52 +03:00
enum fe_status status ;
2012-12-29 02:40:33 +04:00
int i , ret = 0 ;
u32 tuner_freq ;
2013-12-24 20:17:12 +04:00
s16 offset = 0 ;
2012-03-08 01:11:03 +04:00
u8 reg ;
state - > no_lock_count = 0 ;
if ( c - > delivery_system ! = SYS_DVBS ) {
deb_info ( " %s: unsupported delivery "
" system selected (%d) \n " ,
__func__ , c - > delivery_system ) ;
return - EOPNOTSUPP ;
}
/* Set Tuner */
2012-12-29 02:40:33 +04:00
if ( fe - > ops . tuner_ops . set_params )
ret = fe - > ops . tuner_ops . set_params ( fe ) ;
if ( ret < 0 )
return - ENODEV ;
if ( fe - > ops . tuner_ops . get_frequency )
ret = fe - > ops . tuner_ops . get_frequency ( fe , & tuner_freq ) ;
2012-03-08 01:11:03 +04:00
if ( ret < 0 )
return - ENODEV ;
2013-12-24 20:17:12 +04:00
offset = ( s16 ) ( ( s32 ) tuner_freq - c - > frequency ) ;
2012-12-29 02:40:33 +04:00
2013-12-24 20:17:12 +04:00
/* default mclk value 96.4285 * 2 * 1000 = 192857 */
if ( ( ( c - > frequency % 192857 ) > = ( 192857 - 3000 ) ) | |
( c - > frequency % 192857 ) < = 3000 )
ret = m88rs2000_writereg ( state , 0x86 , 0xc2 ) ;
else
ret = m88rs2000_writereg ( state , 0x86 , 0xc6 ) ;
2012-03-08 01:11:03 +04:00
2013-12-24 20:17:12 +04:00
ret | = m88rs2000_set_carrieroffset ( fe , offset ) ;
if ( ret < 0 )
return - ENODEV ;
2012-03-08 01:11:03 +04:00
2013-12-24 20:18:46 +04:00
/* Reset demod by symbol rate */
if ( c - > symbol_rate > 27500000 )
ret = m88rs2000_writereg ( state , 0xf1 , 0xa4 ) ;
else
ret = m88rs2000_writereg ( state , 0xf1 , 0xbf ) ;
ret | = m88rs2000_tab_set ( state , fe_reset ) ;
2012-03-08 01:11:03 +04:00
if ( ret < 0 )
return - ENODEV ;
/* Set FEC */
2013-12-28 21:02:44 +04:00
ret = m88rs2000_set_fec ( state , c - > fec_inner ) ;
2012-12-29 02:40:33 +04:00
ret | = m88rs2000_writereg ( state , 0x85 , 0x1 ) ;
ret | = m88rs2000_writereg ( state , 0x8a , 0xbf ) ;
ret | = m88rs2000_writereg ( state , 0x8d , 0x1e ) ;
ret | = m88rs2000_writereg ( state , 0x90 , 0xf1 ) ;
ret | = m88rs2000_writereg ( state , 0x91 , 0x08 ) ;
2012-03-08 01:11:03 +04:00
if ( ret < 0 )
return - ENODEV ;
/* Set Symbol Rate */
ret = m88rs2000_set_symbolrate ( fe , c - > symbol_rate ) ;
if ( ret < 0 )
return - ENODEV ;
/* Set up Demod */
ret = m88rs2000_tab_set ( state , fe_trigger ) ;
if ( ret < 0 )
return - ENODEV ;
for ( i = 0 ; i < 25 ; i + + ) {
2012-12-29 02:40:33 +04:00
reg = m88rs2000_readreg ( state , 0x8c ) ;
2013-12-28 21:00:40 +04:00
if ( ( reg & 0xee ) = = 0xee ) {
2012-03-08 01:11:03 +04:00
status = FE_HAS_LOCK ;
break ;
}
state - > no_lock_count + + ;
2012-05-14 23:43:50 +04:00
if ( state - > no_lock_count = = 15 ) {
2012-12-29 02:40:33 +04:00
reg = m88rs2000_readreg ( state , 0x70 ) ;
2012-03-08 01:11:03 +04:00
reg ^ = 0x4 ;
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x70 , reg ) ;
2012-03-08 01:11:03 +04:00
state - > no_lock_count = 0 ;
}
msleep ( 20 ) ;
}
if ( status & FE_HAS_LOCK ) {
state - > fec_inner = m88rs2000_get_fec ( state ) ;
/* Uknown suspect SNR level */
2012-12-29 02:40:33 +04:00
reg = m88rs2000_readreg ( state , 0x65 ) ;
2012-03-08 01:11:03 +04:00
}
state - > tuner_frequency = c - > frequency ;
state - > symbol_rate = c - > symbol_rate ;
return 0 ;
}
static int m88rs2000_get_frontend ( struct dvb_frontend * fe )
{
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
struct m88rs2000_state * state = fe - > demodulator_priv ;
c - > fec_inner = state - > fec_inner ;
c - > frequency = state - > tuner_frequency ;
c - > symbol_rate = state - > symbol_rate ;
return 0 ;
}
2014-02-26 06:11:34 +04:00
static int m88rs2000_get_tune_settings ( struct dvb_frontend * fe ,
struct dvb_frontend_tune_settings * tune )
{
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
if ( c - > symbol_rate > 3000000 )
tune - > min_delay_ms = 2000 ;
else
tune - > min_delay_ms = 3000 ;
tune - > step_size = c - > symbol_rate / 16000 ;
tune - > max_drift = c - > symbol_rate / 2000 ;
return 0 ;
}
2012-03-08 01:11:03 +04:00
static int m88rs2000_i2c_gate_ctrl ( struct dvb_frontend * fe , int enable )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
if ( enable )
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x81 , 0x84 ) ;
2012-03-08 01:11:03 +04:00
else
2012-12-29 02:40:33 +04:00
m88rs2000_writereg ( state , 0x81 , 0x81 ) ;
2012-03-08 01:11:03 +04:00
udelay ( 10 ) ;
return 0 ;
}
static void m88rs2000_release ( struct dvb_frontend * fe )
{
struct m88rs2000_state * state = fe - > demodulator_priv ;
kfree ( state ) ;
}
static struct dvb_frontend_ops m88rs2000_ops = {
. delsys = { SYS_DVBS } ,
. info = {
. name = " M88RS2000 DVB-S " ,
. frequency_min = 950000 ,
. frequency_max = 2150000 ,
. frequency_stepsize = 1000 , /* kHz for QPSK frontends */
. frequency_tolerance = 5000 ,
. symbol_rate_min = 1000000 ,
. symbol_rate_max = 45000000 ,
. symbol_rate_tolerance = 500 , /* ppm */
. caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
2014-02-26 06:05:39 +04:00
FE_CAN_QPSK | FE_CAN_INVERSION_AUTO |
2012-03-08 01:11:03 +04:00
FE_CAN_FEC_AUTO
} ,
. release = m88rs2000_release ,
. init = m88rs2000_init ,
. sleep = m88rs2000_sleep ,
. i2c_gate_ctrl = m88rs2000_i2c_gate_ctrl ,
. read_status = m88rs2000_read_status ,
. read_ber = m88rs2000_read_ber ,
. read_signal_strength = m88rs2000_read_signal_strength ,
. read_snr = m88rs2000_read_snr ,
. read_ucblocks = m88rs2000_read_ucblocks ,
. diseqc_send_master_cmd = m88rs2000_send_diseqc_msg ,
. diseqc_send_burst = m88rs2000_send_diseqc_burst ,
. set_tone = m88rs2000_set_tone ,
. set_voltage = m88rs2000_set_voltage ,
. set_frontend = m88rs2000_set_frontend ,
. get_frontend = m88rs2000_get_frontend ,
2014-02-26 06:11:34 +04:00
. get_tune_settings = m88rs2000_get_tune_settings ,
2012-03-08 01:11:03 +04:00
} ;
struct dvb_frontend * m88rs2000_attach ( const struct m88rs2000_config * config ,
struct i2c_adapter * i2c )
{
struct m88rs2000_state * state = NULL ;
/* allocate memory for the internal state */
state = kzalloc ( sizeof ( struct m88rs2000_state ) , GFP_KERNEL ) ;
if ( state = = NULL )
goto error ;
/* setup the state */
state - > config = config ;
state - > i2c = i2c ;
state - > tuner_frequency = 0 ;
state - > symbol_rate = 0 ;
state - > fec_inner = 0 ;
/* create dvb_frontend */
memcpy ( & state - > frontend . ops , & m88rs2000_ops ,
sizeof ( struct dvb_frontend_ops ) ) ;
state - > frontend . demodulator_priv = state ;
return & state - > frontend ;
error :
kfree ( state ) ;
return NULL ;
}
EXPORT_SYMBOL ( m88rs2000_attach ) ;
MODULE_DESCRIPTION ( " M88RS2000 DVB-S Demodulator driver " ) ;
MODULE_AUTHOR ( " Malcolm Priestley tvboxspy@gmail.com " ) ;
MODULE_LICENSE ( " GPL " ) ;
2012-03-14 23:31:26 +04:00
MODULE_VERSION ( " 1.13 " ) ;
2012-03-08 01:11:03 +04:00