2019-05-27 09:55:06 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2013-02-25 15:39:16 +04:00
/*
2015-04-17 03:36:00 +03:00
* Montage Technology M88DS3103 / M88RS6000 demodulator driver
2013-02-25 15:39:16 +04:00
*
* Copyright ( C ) 2013 Antti Palosaari < crope @ iki . fi >
*/
# include "m88ds3103_priv.h"
2016-08-10 00:32:21 +03:00
static const struct dvb_frontend_ops m88ds3103_ops ;
2013-02-25 15:39:16 +04:00
2015-10-04 00:35:14 +03:00
/* write single register with mask */
static int m88ds3103_update_bits ( struct m88ds3103_dev * dev ,
u8 reg , u8 mask , u8 val )
{
int ret ;
u8 tmp ;
/* no need for read if whole reg is written */
if ( mask ! = 0xff ) {
ret = regmap_bulk_read ( dev - > regmap , reg , & tmp , 1 ) ;
if ( ret )
return ret ;
val & = mask ;
tmp & = ~ mask ;
val | = tmp ;
}
return regmap_bulk_write ( dev - > regmap , reg , & val , 1 ) ;
}
2013-12-02 21:08:53 +04:00
/* write reg val table using reg addr auto increment */
2015-04-17 03:36:00 +03:00
static int m88ds3103_wr_reg_val_tab ( struct m88ds3103_dev * dev ,
2013-12-02 21:08:53 +04:00
const struct m88ds3103_reg_val * tab , int tab_len )
{
2015-04-17 03:36:00 +03:00
struct i2c_client * client = dev - > client ;
2013-12-02 21:08:53 +04:00
int ret , i , j ;
u8 buf [ 83 ] ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " tab_len=%d \n " , tab_len ) ;
2013-12-02 21:08:53 +04:00
2014-10-30 11:01:14 +03:00
if ( tab_len > 86 ) {
2013-12-02 21:08:53 +04:00
ret = - EINVAL ;
goto err ;
}
for ( i = 0 , j = 0 ; i < tab_len ; i + + , j + + ) {
buf [ j ] = tab [ i ] . val ;
if ( i = = tab_len - 1 | | tab [ i ] . reg ! = tab [ i + 1 ] . reg - 1 | |
2015-04-17 03:36:00 +03:00
! ( ( j + 1 ) % ( dev - > cfg - > i2c_wr_max - 1 ) ) ) {
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_write ( dev - > regmap , tab [ i ] . reg - j , buf , j + 1 ) ;
2013-12-02 21:08:53 +04:00
if ( ret )
goto err ;
j = - 1 ;
}
}
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-12-02 21:08:53 +04:00
return ret ;
}
2020-02-02 00:48:24 +03:00
/*
* m88ds3103b demod has an internal device related to clocking . First the i2c
* gate must be opened , for one transaction , then writes will be allowed .
*/
static int m88ds3103b_dt_write ( struct m88ds3103_dev * dev , int reg , int data )
{
struct i2c_client * client = dev - > client ;
u8 buf [ ] = { reg , data } ;
u8 val ;
int ret ;
struct i2c_msg msg = {
. addr = dev - > dt_addr , . flags = 0 , . buf = buf , . len = 2
} ;
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x00 ) ;
val = 0x11 ;
ret = regmap_write ( dev - > regmap , 0x03 , val ) ;
if ( ret )
dev_dbg ( & client - > dev , " fail=%d \n " , ret ) ;
ret = i2c_transfer ( dev - > dt_client - > adapter , & msg , 1 ) ;
if ( ret ! = 1 ) {
dev_err ( & client - > dev , " 0x%02x (ret=%i, reg=0x%02x, value=0x%02x) \n " ,
dev - > dt_addr , ret , reg , data ) ;
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x01 ) ;
return - EREMOTEIO ;
}
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x01 ) ;
dev_dbg ( & client - > dev , " 0x%02x reg 0x%02x, value 0x%02x \n " ,
dev - > dt_addr , reg , data ) ;
return 0 ;
}
/*
* m88ds3103b demod has an internal device related to clocking . First the i2c
* gate must be opened , for two transactions , then reads will be allowed .
*/
static int m88ds3103b_dt_read ( struct m88ds3103_dev * dev , u8 reg )
{
struct i2c_client * client = dev - > client ;
int ret ;
u8 val ;
u8 b0 [ ] = { reg } ;
u8 b1 [ ] = { 0 } ;
struct i2c_msg msg [ ] = {
{
. addr = dev - > dt_addr ,
. flags = 0 ,
. buf = b0 ,
. len = 1
} ,
{
. addr = dev - > dt_addr ,
. flags = I2C_M_RD ,
. buf = b1 ,
. len = 1
}
} ;
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x00 ) ;
val = 0x12 ;
ret = regmap_write ( dev - > regmap , 0x03 , val ) ;
if ( ret )
dev_dbg ( & client - > dev , " fail=%d \n " , ret ) ;
ret = i2c_transfer ( dev - > dt_client - > adapter , msg , 2 ) ;
if ( ret ! = 2 ) {
dev_err ( & client - > dev , " 0x%02x (ret=%d, reg=0x%02x) \n " ,
dev - > dt_addr , ret , reg ) ;
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x01 ) ;
return - EREMOTEIO ;
}
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x01 ) ;
dev_dbg ( & client - > dev , " 0x%02x reg 0x%02x, value 0x%02x \n " ,
dev - > dt_addr , reg , b1 [ 0 ] ) ;
return b1 [ 0 ] ;
}
2015-05-26 18:04:00 +03:00
/*
* Get the demodulator AGC PWM voltage setting supplied to the tuner .
*/
int m88ds3103_get_agc_pwm ( struct dvb_frontend * fe , u8 * _agc_pwm )
{
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
unsigned tmp ;
int ret ;
ret = regmap_read ( dev - > regmap , 0x3f , & tmp ) ;
if ( ret = = 0 )
* _agc_pwm = tmp ;
return ret ;
}
EXPORT_SYMBOL ( m88ds3103_get_agc_pwm ) ;
2015-06-07 20:53:52 +03:00
static int m88ds3103_read_status ( struct dvb_frontend * fe ,
enum fe_status * status )
2013-02-25 15:39:16 +04:00
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2013-02-25 15:39:16 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2015-04-14 02:56:13 +03:00
int ret , i , itmp ;
2015-04-17 04:43:52 +03:00
unsigned int utmp ;
2015-04-14 02:56:13 +03:00
u8 buf [ 3 ] ;
2013-02-25 15:39:16 +04:00
* status = 0 ;
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm ) {
2013-02-25 15:39:16 +04:00
ret = - EAGAIN ;
goto err ;
}
switch ( c - > delivery_system ) {
case SYS_DVBS :
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0xd1 , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
if ( ( utmp & 0x07 ) = = 0x07 )
2013-02-25 15:39:16 +04:00
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC |
FE_HAS_LOCK ;
break ;
case SYS_DVBS2 :
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0x0d , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
if ( ( utmp & 0x8f ) = = 0x8f )
2013-02-25 15:39:16 +04:00
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC |
FE_HAS_LOCK ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid delivery_system \n " ) ;
2013-02-25 15:39:16 +04:00
ret = - EINVAL ;
goto err ;
}
2015-04-17 03:36:00 +03:00
dev - > fe_status = * status ;
2015-04-17 04:43:52 +03:00
dev_dbg ( & client - > dev , " lock=%02x status=%02x \n " , utmp , * status ) ;
2013-02-25 15:39:16 +04:00
2015-04-14 02:56:13 +03:00
/* CNR */
2015-04-17 03:36:00 +03:00
if ( dev - > fe_status & FE_HAS_VITERBI ) {
2015-04-14 02:56:13 +03:00
unsigned int cnr , noise , signal , noise_tot , signal_tot ;
cnr = 0 ;
/* more iterations for more accurate estimation */
# define M88DS3103_SNR_ITERATIONS 3
switch ( c - > delivery_system ) {
case SYS_DVBS :
itmp = 0 ;
for ( i = 0 ; i < M88DS3103_SNR_ITERATIONS ; i + + ) {
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0xff , & utmp ) ;
2015-04-14 02:56:13 +03:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
itmp + = utmp ;
2015-04-14 02:56:13 +03:00
}
/* use of single register limits max value to 15 dB */
/* SNR(X) dB = 10 * ln(X) / ln(10) dB */
itmp = DIV_ROUND_CLOSEST ( itmp , 8 * M88DS3103_SNR_ITERATIONS ) ;
if ( itmp )
cnr = div_u64 ( ( u64 ) 10000 * intlog2 ( itmp ) , intlog2 ( 10 ) ) ;
break ;
case SYS_DVBS2 :
noise_tot = 0 ;
signal_tot = 0 ;
for ( i = 0 ; i < M88DS3103_SNR_ITERATIONS ; i + + ) {
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0x8c , buf , 3 ) ;
2015-04-14 02:56:13 +03:00
if ( ret )
goto err ;
noise = buf [ 1 ] < < 6 ; /* [13:6] */
noise | = buf [ 0 ] & 0x3f ; /* [5:0] */
noise > > = 2 ;
signal = buf [ 2 ] * buf [ 2 ] ;
signal > > = 1 ;
noise_tot + = noise ;
signal_tot + = signal ;
}
noise = noise_tot / M88DS3103_SNR_ITERATIONS ;
signal = signal_tot / M88DS3103_SNR_ITERATIONS ;
/* SNR(X) dB = 10 * log10(X) dB */
if ( signal > noise ) {
itmp = signal / noise ;
cnr = div_u64 ( ( u64 ) 10000 * intlog10 ( itmp ) , ( 1 < < 24 ) ) ;
}
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid delivery_system \n " ) ;
2015-04-14 02:56:13 +03:00
ret = - EINVAL ;
goto err ;
}
if ( cnr ) {
c - > cnr . stat [ 0 ] . scale = FE_SCALE_DECIBEL ;
c - > cnr . stat [ 0 ] . svalue = cnr ;
} else {
c - > cnr . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
}
} else {
c - > cnr . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
}
2015-04-14 15:44:20 +03:00
/* BER */
2015-04-17 03:36:00 +03:00
if ( dev - > fe_status & FE_HAS_LOCK ) {
2015-04-14 15:44:20 +03:00
unsigned int utmp , post_bit_error , post_bit_count ;
switch ( c - > delivery_system ) {
case SYS_DVBS :
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xf9 , 0x04 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0xf8 , & utmp ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
/* measurement ready? */
2015-04-17 04:43:52 +03:00
if ( ! ( utmp & 0x10 ) ) {
ret = regmap_bulk_read ( dev - > regmap , 0xf6 , buf , 2 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
post_bit_error = buf [ 1 ] < < 8 | buf [ 0 ] < < 0 ;
post_bit_count = 0x800000 ;
2015-04-17 03:36:00 +03:00
dev - > post_bit_error + = post_bit_error ;
dev - > post_bit_count + = post_bit_count ;
dev - > dvbv3_ber = post_bit_error ;
2015-04-14 15:44:20 +03:00
/* restart measurement */
2015-04-17 04:43:52 +03:00
utmp | = 0x10 ;
ret = regmap_write ( dev - > regmap , 0xf8 , utmp ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
}
break ;
case SYS_DVBS2 :
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0xd5 , buf , 3 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
utmp = buf [ 2 ] < < 16 | buf [ 1 ] < < 8 | buf [ 0 ] < < 0 ;
/* enough data? */
if ( utmp > 4000 ) {
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0xf7 , buf , 2 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
post_bit_error = buf [ 1 ] < < 8 | buf [ 0 ] < < 0 ;
post_bit_count = 32 * utmp ; /* TODO: FEC */
2015-04-17 03:36:00 +03:00
dev - > post_bit_error + = post_bit_error ;
dev - > post_bit_count + = post_bit_count ;
dev - > dvbv3_ber = post_bit_error ;
2015-04-14 15:44:20 +03:00
/* restart measurement */
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xd1 , 0x01 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xf9 , 0x01 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xf9 , 0x00 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xd1 , 0x00 ) ;
2015-04-14 15:44:20 +03:00
if ( ret )
goto err ;
}
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid delivery_system \n " ) ;
2015-04-14 15:44:20 +03:00
ret = - EINVAL ;
goto err ;
}
c - > post_bit_error . stat [ 0 ] . scale = FE_SCALE_COUNTER ;
2015-04-17 03:36:00 +03:00
c - > post_bit_error . stat [ 0 ] . uvalue = dev - > post_bit_error ;
2015-04-14 15:44:20 +03:00
c - > post_bit_count . stat [ 0 ] . scale = FE_SCALE_COUNTER ;
2015-04-17 03:36:00 +03:00
c - > post_bit_count . stat [ 0 ] . uvalue = dev - > post_bit_count ;
2015-04-14 15:44:20 +03:00
} else {
c - > post_bit_error . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
c - > post_bit_count . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
}
2013-02-25 15:39:16 +04:00
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
2020-02-02 00:48:24 +03:00
static int m88ds3103b_select_mclk ( struct m88ds3103_dev * dev )
{
struct i2c_client * client = dev - > client ;
struct dtv_frontend_properties * c = & dev - > fe . dtv_property_cache ;
u32 adc_Freq_MHz [ 3 ] = { 96 , 93 , 99 } ;
u8 reg16_list [ 3 ] = { 96 , 92 , 100 } , reg16 , reg15 ;
u32 offset_MHz [ 3 ] ;
u32 max_offset = 0 ;
u32 old_setting = dev - > mclk ;
u32 tuner_freq_MHz = c - > frequency / 1000 ;
u8 i ;
char big_symbol = 0 ;
big_symbol = ( c - > symbol_rate > 45010000 ) ? 1 : 0 ;
if ( big_symbol ) {
reg16 = 115 ;
} else {
reg16 = 96 ;
/* TODO: IS THIS NECESSARY ? */
for ( i = 0 ; i < 3 ; i + + ) {
offset_MHz [ i ] = tuner_freq_MHz % adc_Freq_MHz [ i ] ;
if ( offset_MHz [ i ] > ( adc_Freq_MHz [ i ] / 2 ) )
offset_MHz [ i ] = adc_Freq_MHz [ i ] - offset_MHz [ i ] ;
if ( offset_MHz [ i ] > max_offset ) {
max_offset = offset_MHz [ i ] ;
reg16 = reg16_list [ i ] ;
dev - > mclk = adc_Freq_MHz [ i ] * 1000 * 1000 ;
if ( big_symbol )
dev - > mclk / = 2 ;
dev_dbg ( & client - > dev , " modifying mclk %u -> %u \n " ,
old_setting , dev - > mclk ) ;
}
}
}
if ( dev - > mclk = = 93000000 )
regmap_write ( dev - > regmap , 0xA0 , 0x42 ) ;
else if ( dev - > mclk = = 96000000 )
regmap_write ( dev - > regmap , 0xA0 , 0x44 ) ;
else if ( dev - > mclk = = 99000000 )
regmap_write ( dev - > regmap , 0xA0 , 0x46 ) ;
else if ( dev - > mclk = = 110250000 )
regmap_write ( dev - > regmap , 0xA0 , 0x4E ) ;
else
regmap_write ( dev - > regmap , 0xA0 , 0x44 ) ;
reg15 = m88ds3103b_dt_read ( dev , 0x15 ) ;
m88ds3103b_dt_write ( dev , 0x05 , 0x40 ) ;
m88ds3103b_dt_write ( dev , 0x11 , 0x08 ) ;
if ( big_symbol )
reg15 | = 0x02 ;
else
reg15 & = ~ 0x02 ;
m88ds3103b_dt_write ( dev , 0x15 , reg15 ) ;
m88ds3103b_dt_write ( dev , 0x16 , reg16 ) ;
usleep_range ( 5000 , 5500 ) ;
m88ds3103b_dt_write ( dev , 0x05 , 0x00 ) ;
m88ds3103b_dt_write ( dev , 0x11 , ( u8 ) ( big_symbol ? 0x0E : 0x0A ) ) ;
usleep_range ( 5000 , 5500 ) ;
return 0 ;
}
static int m88ds3103b_set_mclk ( struct m88ds3103_dev * dev , u32 mclk_khz )
{
u8 reg11 = 0x0A , reg15 , reg16 , reg1D , reg1E , reg1F , tmp ;
u8 sm , f0 = 0 , f1 = 0 , f2 = 0 , f3 = 0 ;
u16 pll_div_fb , N ;
u32 div ;
reg15 = m88ds3103b_dt_read ( dev , 0x15 ) ;
reg16 = m88ds3103b_dt_read ( dev , 0x16 ) ;
reg1D = m88ds3103b_dt_read ( dev , 0x1D ) ;
if ( dev - > cfg - > ts_mode ! = M88DS3103_TS_SERIAL ) {
if ( reg16 = = 92 )
tmp = 93 ;
else if ( reg16 = = 100 )
tmp = 99 ;
else
tmp = 96 ;
mclk_khz * = tmp ;
mclk_khz / = 96 ;
}
pll_div_fb = ( reg15 & 0x01 ) < < 8 ;
pll_div_fb + = reg16 ;
pll_div_fb + = 32 ;
div = 9000 * pll_div_fb * 4 ;
div / = mclk_khz ;
if ( dev - > cfg - > ts_mode = = M88DS3103_TS_SERIAL ) {
reg11 | = 0x02 ;
if ( div < = 32 ) {
N = 2 ;
f0 = 0 ;
f1 = div / N ;
f2 = div - f1 ;
f3 = 0 ;
} else if ( div < = 34 ) {
N = 3 ;
f0 = div / N ;
f1 = ( div - f0 ) / ( N - 1 ) ;
f2 = div - f0 - f1 ;
f3 = 0 ;
} else if ( div < = 64 ) {
N = 4 ;
f0 = div / N ;
f1 = ( div - f0 ) / ( N - 1 ) ;
f2 = ( div - f0 - f1 ) / ( N - 2 ) ;
f3 = div - f0 - f1 - f2 ;
} else {
N = 4 ;
f0 = 16 ;
f1 = 16 ;
f2 = 16 ;
f3 = 16 ;
}
if ( f0 = = 16 )
f0 = 0 ;
else if ( ( f0 < 8 ) & & ( f0 ! = 0 ) )
f0 = 8 ;
if ( f1 = = 16 )
f1 = 0 ;
else if ( ( f1 < 8 ) & & ( f1 ! = 0 ) )
f1 = 8 ;
if ( f2 = = 16 )
f2 = 0 ;
else if ( ( f2 < 8 ) & & ( f2 ! = 0 ) )
f2 = 8 ;
if ( f3 = = 16 )
f3 = 0 ;
else if ( ( f3 < 8 ) & & ( f3 ! = 0 ) )
f3 = 8 ;
} else {
reg11 & = ~ 0x02 ;
if ( div < = 32 ) {
N = 2 ;
f0 = 0 ;
f1 = div / N ;
f2 = div - f1 ;
f3 = 0 ;
} else if ( div < = 48 ) {
N = 3 ;
f0 = div / N ;
f1 = ( div - f0 ) / ( N - 1 ) ;
f2 = div - f0 - f1 ;
f3 = 0 ;
} else if ( div < = 64 ) {
N = 4 ;
f0 = div / N ;
f1 = ( div - f0 ) / ( N - 1 ) ;
f2 = ( div - f0 - f1 ) / ( N - 2 ) ;
f3 = div - f0 - f1 - f2 ;
} else {
N = 4 ;
f0 = 16 ;
f1 = 16 ;
f2 = 16 ;
f3 = 16 ;
}
if ( f0 = = 16 )
f0 = 0 ;
else if ( ( f0 < 9 ) & & ( f0 ! = 0 ) )
f0 = 9 ;
if ( f1 = = 16 )
f1 = 0 ;
else if ( ( f1 < 9 ) & & ( f1 ! = 0 ) )
f1 = 9 ;
if ( f2 = = 16 )
f2 = 0 ;
else if ( ( f2 < 9 ) & & ( f2 ! = 0 ) )
f2 = 9 ;
if ( f3 = = 16 )
f3 = 0 ;
else if ( ( f3 < 9 ) & & ( f3 ! = 0 ) )
f3 = 9 ;
}
sm = N - 1 ;
/* Write to registers */
//reg15 &= 0x01;
//reg15 |= (pll_div_fb >> 8) & 0x01;
//reg16 = pll_div_fb & 0xFF;
reg1D & = ~ 0x03 ;
reg1D | = sm ;
reg1D | = 0x80 ;
reg1E = ( ( f3 < < 4 ) + f2 ) & 0xFF ;
reg1F = ( ( f1 < < 4 ) + f0 ) & 0xFF ;
m88ds3103b_dt_write ( dev , 0x05 , 0x40 ) ;
m88ds3103b_dt_write ( dev , 0x11 , 0x08 ) ;
m88ds3103b_dt_write ( dev , 0x1D , reg1D ) ;
m88ds3103b_dt_write ( dev , 0x1E , reg1E ) ;
m88ds3103b_dt_write ( dev , 0x1F , reg1F ) ;
m88ds3103b_dt_write ( dev , 0x17 , 0xc1 ) ;
m88ds3103b_dt_write ( dev , 0x17 , 0x81 ) ;
usleep_range ( 5000 , 5500 ) ;
m88ds3103b_dt_write ( dev , 0x05 , 0x00 ) ;
m88ds3103b_dt_write ( dev , 0x11 , 0x0A ) ;
usleep_range ( 5000 , 5500 ) ;
return 0 ;
}
2013-02-25 15:39:16 +04:00
static int m88ds3103_set_frontend ( struct dvb_frontend * fe )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2013-02-25 15:39:16 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2013-12-02 21:08:53 +04:00
int ret , len ;
2013-02-25 15:39:16 +04:00
const struct m88ds3103_reg_val * init ;
2014-11-05 17:59:07 +03:00
u8 u8tmp , u8tmp1 = 0 , u8tmp2 = 0 ; /* silence compiler warning */
2014-10-30 11:01:14 +03:00
u8 buf [ 3 ] ;
2016-06-30 02:39:46 +03:00
u16 u16tmp ;
2020-02-02 00:48:24 +03:00
u32 tuner_frequency_khz , target_mclk , u32tmp ;
2013-02-25 15:39:16 +04:00
s32 s32tmp ;
2019-01-14 00:13:47 +03:00
static const struct reg_sequence reset_buf [ ] = {
{ 0x07 , 0x80 } , { 0x07 , 0x00 }
} ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev ,
" delivery_system=%d modulation=%d frequency=%u symbol_rate=%d inversion=%d pilot=%d rolloff=%d \n " ,
c - > delivery_system , c - > modulation , c - > frequency , c - > symbol_rate ,
c - > inversion , c - > pilot , c - > rolloff ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm ) {
2013-02-25 15:39:16 +04:00
ret = - EAGAIN ;
goto err ;
}
2014-10-30 11:01:14 +03:00
/* reset */
2019-01-14 00:13:47 +03:00
ret = regmap_multi_reg_write ( dev - > regmap , reset_buf , 2 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
/* Disable demod clock path */
2015-04-17 03:36:00 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID ) {
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
ret = regmap_read ( dev - > regmap , 0xb2 , & u32tmp ) ;
if ( ret )
goto err ;
if ( u32tmp = = 0x01 ) {
ret = regmap_write ( dev - > regmap , 0x00 , 0x00 ) ;
if ( ret )
goto err ;
ret = regmap_write ( dev - > regmap , 0xb2 , 0x00 ) ;
if ( ret )
goto err ;
}
}
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x06 , 0xe0 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
}
2013-02-25 15:39:16 +04:00
/* program tuner */
if ( fe - > ops . tuner_ops . set_params ) {
ret = fe - > ops . tuner_ops . set_params ( fe ) ;
if ( ret )
goto err ;
}
if ( fe - > ops . tuner_ops . get_frequency ) {
2016-06-30 02:39:47 +03:00
ret = fe - > ops . tuner_ops . get_frequency ( fe , & tuner_frequency_khz ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2014-02-01 19:58:28 +04:00
} else {
/*
* Use nominal target frequency as tuner driver does not provide
* actual frequency used . Carrier offset calculation is not
* valid .
*/
2016-06-30 02:39:47 +03:00
tuner_frequency_khz = c - > frequency ;
2013-02-25 15:39:16 +04:00
}
2020-02-02 00:48:24 +03:00
/* set M88RS6000/DS3103B demod main mclk and ts mclk from tuner die */
2015-04-17 03:36:00 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID ) {
2014-10-30 11:01:14 +03:00
if ( c - > symbol_rate > 45010000 )
2016-06-30 02:39:47 +03:00
dev - > mclk = 110250000 ;
2014-10-30 11:01:14 +03:00
else
2016-06-30 02:39:47 +03:00
dev - > mclk = 96000000 ;
2013-02-25 15:39:16 +04:00
2014-10-30 11:01:14 +03:00
if ( c - > delivery_system = = SYS_DVBS )
2016-06-30 02:39:47 +03:00
target_mclk = 96000000 ;
2014-10-30 11:01:14 +03:00
else
2016-06-30 02:39:47 +03:00
target_mclk = 144000000 ;
2014-10-30 11:01:14 +03:00
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
m88ds3103b_select_mclk ( dev ) ;
m88ds3103b_set_mclk ( dev , target_mclk / 1000 ) ;
}
2014-10-30 11:01:14 +03:00
/* Enable demod clock path */
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x06 , 0x00 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
usleep_range ( 10000 , 20000 ) ;
} else {
/* set M88DS3103 mclk and ts mclk. */
2016-06-30 02:39:47 +03:00
dev - > mclk = 96000000 ;
2014-10-30 11:01:14 +03:00
2015-04-17 03:36:00 +03:00
switch ( dev - > cfg - > ts_mode ) {
2014-11-05 17:59:07 +03:00
case M88DS3103_TS_SERIAL :
case M88DS3103_TS_SERIAL_D7 :
2015-04-17 03:36:00 +03:00
target_mclk = dev - > cfg - > ts_clk ;
2014-11-05 17:59:07 +03:00
break ;
case M88DS3103_TS_PARALLEL :
case M88DS3103_TS_CI :
if ( c - > delivery_system = = SYS_DVBS )
2016-06-30 02:39:47 +03:00
target_mclk = 96000000 ;
2014-11-05 17:59:07 +03:00
else {
2014-10-30 11:01:14 +03:00
if ( c - > symbol_rate < 18000000 )
2016-06-30 02:39:47 +03:00
target_mclk = 96000000 ;
2014-10-30 11:01:14 +03:00
else if ( c - > symbol_rate < 28000000 )
2016-06-30 02:39:47 +03:00
target_mclk = 144000000 ;
2014-10-30 11:01:14 +03:00
else
2016-06-30 02:39:47 +03:00
target_mclk = 192000000 ;
2014-10-30 11:01:14 +03:00
}
2014-11-05 17:59:07 +03:00
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid ts_mode \n " ) ;
2014-11-05 17:59:07 +03:00
ret = - EINVAL ;
goto err ;
2014-10-30 11:01:14 +03:00
}
switch ( target_mclk ) {
2016-06-30 02:39:47 +03:00
case 96000000 :
2014-10-30 11:01:14 +03:00
u8tmp1 = 0x02 ; /* 0b10 */
u8tmp2 = 0x01 ; /* 0b01 */
break ;
2016-06-30 02:39:47 +03:00
case 144000000 :
2014-10-30 11:01:14 +03:00
u8tmp1 = 0x00 ; /* 0b00 */
u8tmp2 = 0x01 ; /* 0b01 */
break ;
2016-06-30 02:39:47 +03:00
case 192000000 :
2014-10-30 11:01:14 +03:00
u8tmp1 = 0x03 ; /* 0b11 */
u8tmp2 = 0x00 ; /* 0b00 */
break ;
}
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x22 , 0xc0 , u8tmp1 < < 6 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x24 , 0xc0 , u8tmp2 < < 6 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
}
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xb2 , 0x01 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x00 , 0x01 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
switch ( c - > delivery_system ) {
case SYS_DVBS :
2015-04-17 03:36:00 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID ) {
2014-10-30 11:01:14 +03:00
len = ARRAY_SIZE ( m88rs6000_dvbs_init_reg_vals ) ;
init = m88rs6000_dvbs_init_reg_vals ;
} else {
len = ARRAY_SIZE ( m88ds3103_dvbs_init_reg_vals ) ;
init = m88ds3103_dvbs_init_reg_vals ;
}
2013-02-25 15:39:16 +04:00
break ;
case SYS_DVBS2 :
2015-04-17 03:36:00 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID ) {
2014-10-30 11:01:14 +03:00
len = ARRAY_SIZE ( m88rs6000_dvbs2_init_reg_vals ) ;
init = m88rs6000_dvbs2_init_reg_vals ;
} else {
len = ARRAY_SIZE ( m88ds3103_dvbs2_init_reg_vals ) ;
init = m88ds3103_dvbs2_init_reg_vals ;
2013-02-25 15:39:16 +04:00
}
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid delivery_system \n " ) ;
2013-02-25 15:39:16 +04:00
ret = - EINVAL ;
goto err ;
}
/* program init table */
2015-04-17 03:36:00 +03:00
if ( c - > delivery_system ! = dev - > delivery_system ) {
ret = m88ds3103_wr_reg_val_tab ( dev , init , len ) ;
2013-12-02 21:08:53 +04:00
if ( ret )
goto err ;
2013-02-25 15:39:16 +04:00
}
2015-04-17 03:36:00 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID ) {
2016-06-30 02:39:47 +03:00
if ( c - > delivery_system = = SYS_DVBS2 & &
c - > symbol_rate < = 5000000 ) {
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xc0 , 0x04 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
buf [ 0 ] = 0x09 ;
buf [ 1 ] = 0x22 ;
buf [ 2 ] = 0x88 ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_write ( dev - > regmap , 0x8a , buf , 3 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
}
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x9d , 0x08 , 0x08 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
buf [ 0 ] = m88ds3103b_dt_read ( dev , 0x15 ) ;
buf [ 1 ] = m88ds3103b_dt_read ( dev , 0x16 ) ;
if ( c - > symbol_rate > 45010000 ) {
buf [ 0 ] & = ~ 0x03 ;
buf [ 0 ] | = 0x02 ;
buf [ 0 ] | = ( ( 147 - 32 ) > > 8 ) & 0x01 ;
buf [ 1 ] = ( 147 - 32 ) & 0xFF ;
dev - > mclk = 110250 * 1000 ;
} else {
buf [ 0 ] & = ~ 0x03 ;
buf [ 0 ] | = ( ( 128 - 32 ) > > 8 ) & 0x01 ;
buf [ 1 ] = ( 128 - 32 ) & 0xFF ;
dev - > mclk = 96000 * 1000 ;
}
m88ds3103b_dt_write ( dev , 0x15 , buf [ 0 ] ) ;
m88ds3103b_dt_write ( dev , 0x16 , buf [ 1 ] ) ;
regmap_read ( dev - > regmap , 0x30 , & u32tmp ) ;
u32tmp & = ~ 0x80 ;
regmap_write ( dev - > regmap , 0x30 , u32tmp & 0xff ) ;
}
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xf1 , 0x01 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype ! = M88DS3103_CHIPTYPE_3103B ) {
ret = m88ds3103_update_bits ( dev , 0x30 , 0x80 , 0x80 ) ;
if ( ret )
goto err ;
}
2014-10-30 11:01:14 +03:00
}
2015-04-17 03:36:00 +03:00
switch ( dev - > cfg - > ts_mode ) {
2013-02-25 15:39:16 +04:00
case M88DS3103_TS_SERIAL :
u8tmp1 = 0x00 ;
2014-08-11 08:22:45 +04:00
u8tmp = 0x06 ;
2013-02-25 15:39:16 +04:00
break ;
case M88DS3103_TS_SERIAL_D7 :
u8tmp1 = 0x20 ;
2014-08-11 08:22:45 +04:00
u8tmp = 0x06 ;
2013-02-25 15:39:16 +04:00
break ;
case M88DS3103_TS_PARALLEL :
2014-08-11 08:22:45 +04:00
u8tmp = 0x02 ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
u8tmp = 0x01 ;
u8tmp1 = 0x01 ;
}
2013-02-25 15:39:16 +04:00
break ;
case M88DS3103_TS_CI :
2014-08-11 08:22:45 +04:00
u8tmp = 0x03 ;
2013-02-25 15:39:16 +04:00
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid ts_mode \n " ) ;
2013-02-25 15:39:16 +04:00
ret = - EINVAL ;
goto err ;
}
2015-04-17 03:36:00 +03:00
if ( dev - > cfg - > ts_clk_pol )
2014-08-11 08:22:45 +04:00
u8tmp | = 0x40 ;
2013-02-25 15:39:16 +04:00
/* TS mode */
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xfd , u8tmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 03:36:00 +03:00
switch ( dev - > cfg - > ts_mode ) {
2013-02-25 15:39:16 +04:00
case M88DS3103_TS_SERIAL :
case M88DS3103_TS_SERIAL_D7 :
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x29 , 0x20 , u8tmp1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2016-06-30 02:39:46 +03:00
u16tmp = 0 ;
u8tmp1 = 0x3f ;
u8tmp2 = 0x3f ;
2014-11-05 17:59:07 +03:00
break ;
2020-02-02 00:48:24 +03:00
case M88DS3103_TS_PARALLEL :
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
ret = m88ds3103_update_bits ( dev , 0x29 , 0x01 , u8tmp1 ) ;
if ( ret )
goto err ;
}
/* fall through */
2014-11-05 17:59:07 +03:00
default :
2016-06-30 02:39:46 +03:00
u16tmp = DIV_ROUND_UP ( target_mclk , dev - > cfg - > ts_clk ) ;
u8tmp1 = u16tmp / 2 - 1 ;
u8tmp2 = DIV_ROUND_UP ( u16tmp , 2 ) - 1 ;
2013-02-25 15:39:16 +04:00
}
2016-06-30 02:39:47 +03:00
dev_dbg ( & client - > dev , " target_mclk=%u ts_clk=%u ts_clk_divide_ratio=%u \n " ,
2016-06-30 02:39:46 +03:00
target_mclk , dev - > cfg - > ts_clk , u16tmp ) ;
2013-02-25 15:39:16 +04:00
/* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */
/* u8tmp2[5:0] => ea[5:0] */
2016-06-30 02:39:46 +03:00
u8tmp = ( u8tmp1 > > 2 ) & 0x0f ;
ret = regmap_update_bits ( dev - > regmap , 0xfe , 0x0f , u8tmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
u8tmp = ( ( u8tmp1 & 0x03 ) < < 6 ) | u8tmp2 > > 0 ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xea , u8tmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
if ( c - > symbol_rate < = 3000000 )
u8tmp = 0x20 ;
else if ( c - > symbol_rate < = 10000000 )
u8tmp = 0x10 ;
else
u8tmp = 0x06 ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B )
m88ds3103b_set_mclk ( dev , target_mclk / 1000 ) ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xc3 , 0x08 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xc8 , u8tmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xc4 , 0x08 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xc7 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2016-06-30 02:39:47 +03:00
u16tmp = DIV_ROUND_CLOSEST_ULL ( ( u64 ) c - > symbol_rate * 0x10000 , dev - > mclk ) ;
2013-02-25 15:39:16 +04:00
buf [ 0 ] = ( u16tmp > > 0 ) & 0xff ;
buf [ 1 ] = ( u16tmp > > 8 ) & 0xff ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_write ( dev - > regmap , 0x61 , buf , 2 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x4d , 0x02 , dev - > cfg - > spec_inv < < 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x30 , 0x10 , dev - > cfg - > agc_inv < < 4 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x33 , dev - > cfg - > agc ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
/* enable/disable 192M LDPC clock */
ret = m88ds3103_update_bits ( dev , 0x29 , 0x10 ,
( c - > delivery_system = = SYS_DVBS ) ? 0x10 : 0x0 ) ;
if ( ret )
goto err ;
ret = m88ds3103_update_bits ( dev , 0xc9 , 0x08 , 0x08 ) ;
}
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " carrier offset=%d \n " ,
2016-06-30 02:39:47 +03:00
( tuner_frequency_khz - c - > frequency ) ) ;
2013-02-25 15:39:16 +04:00
2016-06-30 02:39:47 +03:00
/* Use 32-bit calc as there is no s64 version of DIV_ROUND_CLOSEST() */
s32tmp = 0x10000 * ( tuner_frequency_khz - c - > frequency ) ;
s32tmp = DIV_ROUND_CLOSEST ( s32tmp , dev - > mclk / 1000 ) ;
2013-02-25 15:39:16 +04:00
buf [ 0 ] = ( s32tmp > > 0 ) & 0xff ;
buf [ 1 ] = ( s32tmp > > 8 ) & 0xff ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_write ( dev - > regmap , 0x5e , buf , 2 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x00 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xb2 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 03:36:00 +03:00
dev - > delivery_system = c - > delivery_system ;
2013-02-25 15:39:16 +04:00
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
static int m88ds3103_init ( struct dvb_frontend * fe )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2015-04-14 02:56:13 +03:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2016-06-30 02:39:48 +03:00
int ret , len , rem ;
2015-04-17 04:43:52 +03:00
unsigned int utmp ;
2016-06-30 02:39:48 +03:00
const struct firmware * firmware ;
const char * name ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-02-25 15:39:16 +04:00
/* set cold state by default */
2015-04-17 03:36:00 +03:00
dev - > warm = false ;
2013-02-25 15:39:16 +04:00
/* wake up device from sleep */
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x08 , 0x01 , 0x01 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x04 , 0x01 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x23 , 0x10 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
/* firmware status */
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0xb9 , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
dev_dbg ( & client - > dev , " firmware=%02x \n " , utmp ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
if ( utmp )
2016-06-30 02:39:48 +03:00
goto warm ;
2013-02-25 15:39:16 +04:00
2020-02-02 00:48:24 +03:00
/* global reset, global diseqc reset, global fec reset */
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x07 , 0xe0 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x07 , 0x00 ) ;
2014-10-30 11:01:14 +03:00
if ( ret )
goto err ;
2013-02-25 15:39:16 +04:00
/* cold state - try to download firmware */
2015-04-17 03:36:00 +03:00
dev_info ( & client - > dev , " found a '%s' in cold state \n " ,
2020-02-02 00:48:24 +03:00
dev - > fe . ops . info . name ) ;
2013-02-25 15:39:16 +04:00
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B )
name = M88DS3103B_FIRMWARE ;
else if ( dev - > chip_id = = M88RS6000_CHIP_ID )
2016-06-30 02:39:48 +03:00
name = M88RS6000_FIRMWARE ;
2014-10-30 11:01:14 +03:00
else
2016-06-30 02:39:48 +03:00
name = M88DS3103_FIRMWARE ;
2020-02-02 00:48:24 +03:00
2013-02-25 15:39:16 +04:00
/* request the firmware, this will block and timeout */
2016-06-30 02:39:48 +03:00
ret = request_firmware ( & firmware , name , & client - > dev ) ;
2013-02-25 15:39:16 +04:00
if ( ret ) {
2016-06-30 02:39:48 +03:00
dev_err ( & client - > dev , " firmware file '%s' not found \n " , name ) ;
2013-02-25 15:39:16 +04:00
goto err ;
}
2016-06-30 02:39:48 +03:00
dev_info ( & client - > dev , " downloading firmware from file '%s' \n " , name ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xb2 , 0x01 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2016-06-30 02:39:48 +03:00
goto err_release_firmware ;
2013-02-25 15:39:16 +04:00
2016-06-30 02:39:48 +03:00
for ( rem = firmware - > size ; rem > 0 ; rem - = ( dev - > cfg - > i2c_wr_max - 1 ) ) {
len = min ( dev - > cfg - > i2c_wr_max - 1 , rem ) ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_write ( dev - > regmap , 0xb0 ,
2016-06-30 02:39:48 +03:00
& firmware - > data [ firmware - > size - rem ] ,
len ) ;
2013-02-25 15:39:16 +04:00
if ( ret ) {
2016-06-30 02:39:48 +03:00
dev_err ( & client - > dev , " firmware download failed %d \n " ,
2015-04-17 03:36:00 +03:00
ret ) ;
2016-06-30 02:39:48 +03:00
goto err_release_firmware ;
2013-02-25 15:39:16 +04:00
}
}
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xb2 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2016-06-30 02:39:48 +03:00
goto err_release_firmware ;
2013-02-25 15:39:16 +04:00
2016-06-30 02:39:48 +03:00
release_firmware ( firmware ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0xb9 , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
if ( ! utmp ) {
2016-06-30 02:39:48 +03:00
ret = - EINVAL ;
2015-04-17 03:36:00 +03:00
dev_info ( & client - > dev , " firmware did not run \n " ) ;
2013-02-25 15:39:16 +04:00
goto err ;
}
2015-04-17 03:36:00 +03:00
dev_info ( & client - > dev , " found a '%s' in warm state \n " ,
2020-02-02 00:48:24 +03:00
dev - > fe . ops . info . name ) ;
2015-04-17 03:36:00 +03:00
dev_info ( & client - > dev , " firmware version: %X.%X \n " ,
2015-04-17 04:43:52 +03:00
( utmp > > 4 ) & 0xf , ( utmp > > 0 & 0xf ) ) ;
2013-02-25 15:39:16 +04:00
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
m88ds3103b_dt_write ( dev , 0x21 , 0x92 ) ;
m88ds3103b_dt_write ( dev , 0x15 , 0x6C ) ;
m88ds3103b_dt_write ( dev , 0x17 , 0xC1 ) ;
m88ds3103b_dt_write ( dev , 0x17 , 0x81 ) ;
}
2016-06-30 02:39:48 +03:00
warm :
2013-02-25 15:39:16 +04:00
/* warm state */
2015-04-17 03:36:00 +03:00
dev - > warm = true ;
2015-04-14 02:56:13 +03:00
/* init stats here in order signal app which stats are supported */
c - > cnr . len = 1 ;
c - > cnr . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
2015-04-14 15:44:20 +03:00
c - > post_bit_error . len = 1 ;
c - > post_bit_error . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
c - > post_bit_count . len = 1 ;
c - > post_bit_count . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
return 0 ;
2016-06-30 02:39:48 +03:00
err_release_firmware :
release_firmware ( firmware ) ;
2014-11-20 01:20:51 +03:00
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
static int m88ds3103_sleep ( struct dvb_frontend * fe )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2013-02-25 15:39:16 +04:00
int ret ;
2015-04-17 04:43:52 +03:00
unsigned int utmp ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
dev - > fe_status = 0 ;
dev - > delivery_system = SYS_UNDEFINED ;
2013-02-25 15:39:16 +04:00
/* TS Hi-Z */
2015-04-17 03:36:00 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID )
2015-04-17 04:43:52 +03:00
utmp = 0x29 ;
2014-10-30 11:01:14 +03:00
else
2015-04-17 04:43:52 +03:00
utmp = 0x27 ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , utmp , 0x01 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
/* sleep */
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x08 , 0x01 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x04 , 0x01 , 0x01 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x23 , 0x10 , 0x10 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
2016-02-04 17:58:30 +03:00
static int m88ds3103_get_frontend ( struct dvb_frontend * fe ,
struct dtv_frontend_properties * c )
2013-02-25 15:39:16 +04:00
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2013-02-25 15:39:16 +04:00
int ret ;
u8 buf [ 3 ] ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm | | ! ( dev - > fe_status & FE_HAS_LOCK ) ) {
2015-04-14 03:00:09 +03:00
ret = 0 ;
2013-02-25 15:39:16 +04:00
goto err ;
}
switch ( c - > delivery_system ) {
case SYS_DVBS :
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0xe0 , & buf [ 0 ] , 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0xe6 , & buf [ 1 ] , 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
switch ( ( buf [ 0 ] > > 2 ) & 0x01 ) {
case 0 :
c - > inversion = INVERSION_OFF ;
break ;
case 1 :
c - > inversion = INVERSION_ON ;
break ;
}
switch ( ( buf [ 1 ] > > 5 ) & 0x07 ) {
case 0 :
c - > fec_inner = FEC_7_8 ;
break ;
case 1 :
c - > fec_inner = FEC_5_6 ;
break ;
case 2 :
c - > fec_inner = FEC_3_4 ;
break ;
case 3 :
c - > fec_inner = FEC_2_3 ;
break ;
case 4 :
c - > fec_inner = FEC_1_2 ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid fec_inner \n " ) ;
2013-02-25 15:39:16 +04:00
}
c - > modulation = QPSK ;
break ;
case SYS_DVBS2 :
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0x7e , & buf [ 0 ] , 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0x89 , & buf [ 1 ] , 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0xf2 , & buf [ 2 ] , 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
switch ( ( buf [ 0 ] > > 0 ) & 0x0f ) {
case 2 :
c - > fec_inner = FEC_2_5 ;
break ;
case 3 :
c - > fec_inner = FEC_1_2 ;
break ;
case 4 :
c - > fec_inner = FEC_3_5 ;
break ;
case 5 :
c - > fec_inner = FEC_2_3 ;
break ;
case 6 :
c - > fec_inner = FEC_3_4 ;
break ;
case 7 :
c - > fec_inner = FEC_4_5 ;
break ;
case 8 :
c - > fec_inner = FEC_5_6 ;
break ;
case 9 :
c - > fec_inner = FEC_8_9 ;
break ;
case 10 :
c - > fec_inner = FEC_9_10 ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid fec_inner \n " ) ;
2013-02-25 15:39:16 +04:00
}
switch ( ( buf [ 0 ] > > 5 ) & 0x01 ) {
case 0 :
c - > pilot = PILOT_OFF ;
break ;
case 1 :
c - > pilot = PILOT_ON ;
break ;
}
switch ( ( buf [ 0 ] > > 6 ) & 0x07 ) {
case 0 :
c - > modulation = QPSK ;
break ;
case 1 :
c - > modulation = PSK_8 ;
break ;
case 2 :
c - > modulation = APSK_16 ;
break ;
case 3 :
c - > modulation = APSK_32 ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid modulation \n " ) ;
2013-02-25 15:39:16 +04:00
}
switch ( ( buf [ 1 ] > > 7 ) & 0x01 ) {
case 0 :
c - > inversion = INVERSION_OFF ;
break ;
case 1 :
c - > inversion = INVERSION_ON ;
break ;
}
switch ( ( buf [ 2 ] > > 0 ) & 0x03 ) {
case 0 :
c - > rolloff = ROLLOFF_35 ;
break ;
case 1 :
c - > rolloff = ROLLOFF_25 ;
break ;
case 2 :
c - > rolloff = ROLLOFF_20 ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid rolloff \n " ) ;
2013-02-25 15:39:16 +04:00
}
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid delivery_system \n " ) ;
2013-02-25 15:39:16 +04:00
ret = - EINVAL ;
goto err ;
}
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_read ( dev - > regmap , 0x6d , buf , 2 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2016-06-30 02:39:47 +03:00
c - > symbol_rate = DIV_ROUND_CLOSEST_ULL ( ( u64 ) ( buf [ 1 ] < < 8 | buf [ 0 ] < < 0 ) * dev - > mclk , 0x10000 ) ;
2013-02-25 15:39:16 +04:00
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
static int m88ds3103_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2014-08-22 04:38:29 +04:00
2015-04-14 02:56:13 +03:00
if ( c - > cnr . stat [ 0 ] . scale = = FE_SCALE_DECIBEL )
* snr = div_s64 ( c - > cnr . stat [ 0 ] . svalue , 100 ) ;
else
* snr = 0 ;
2013-02-25 15:39:16 +04:00
return 0 ;
}
2014-07-10 15:17:59 +04:00
static int m88ds3103_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
* ber = dev - > dvbv3_ber ;
2014-07-10 15:17:59 +04:00
return 0 ;
}
2013-02-25 15:39:16 +04:00
static int m88ds3103_set_tone ( struct dvb_frontend * fe ,
2015-06-07 20:53:52 +03:00
enum fe_sec_tone_mode fe_sec_tone_mode )
2013-02-25 15:39:16 +04:00
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2013-02-25 15:39:16 +04:00
int ret ;
2015-04-17 04:43:52 +03:00
unsigned int utmp , tone , reg_a1_mask ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " fe_sec_tone_mode=%d \n " , fe_sec_tone_mode ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm ) {
2013-02-25 15:39:16 +04:00
ret = - EAGAIN ;
goto err ;
}
switch ( fe_sec_tone_mode ) {
case SEC_TONE_ON :
tone = 0 ;
2014-02-02 00:28:21 +04:00
reg_a1_mask = 0x47 ;
2013-02-25 15:39:16 +04:00
break ;
case SEC_TONE_OFF :
tone = 1 ;
reg_a1_mask = 0x00 ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid fe_sec_tone_mode \n " ) ;
2013-02-25 15:39:16 +04:00
ret = - EINVAL ;
goto err ;
}
2015-04-17 04:43:52 +03:00
utmp = tone < < 7 | dev - > cfg - > envelope_mode < < 5 ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa2 , 0xe0 , utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
utmp = 1 < < 2 ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa1 , reg_a1_mask , utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
2014-08-11 08:22:45 +04:00
static int m88ds3103_set_voltage ( struct dvb_frontend * fe ,
2015-06-07 20:53:52 +03:00
enum fe_sec_voltage fe_sec_voltage )
2014-08-11 08:22:45 +04:00
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2014-08-22 04:06:13 +04:00
int ret ;
2015-04-17 04:43:52 +03:00
unsigned int utmp ;
2014-08-22 04:06:13 +04:00
bool voltage_sel , voltage_dis ;
2014-08-11 08:22:45 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " fe_sec_voltage=%d \n " , fe_sec_voltage ) ;
2014-08-11 08:22:45 +04:00
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm ) {
2014-08-22 04:06:13 +04:00
ret = - EAGAIN ;
goto err ;
}
2014-08-11 08:22:45 +04:00
2014-08-22 04:06:13 +04:00
switch ( fe_sec_voltage ) {
2014-08-11 08:22:45 +04:00
case SEC_VOLTAGE_18 :
2014-09-03 22:24:29 +04:00
voltage_sel = true ;
voltage_dis = false ;
2014-08-11 08:22:45 +04:00
break ;
case SEC_VOLTAGE_13 :
2014-09-03 22:24:29 +04:00
voltage_sel = false ;
voltage_dis = false ;
2014-08-11 08:22:45 +04:00
break ;
case SEC_VOLTAGE_OFF :
2014-09-03 22:24:29 +04:00
voltage_sel = false ;
voltage_dis = true ;
2014-08-11 08:22:45 +04:00
break ;
2014-08-22 04:06:13 +04:00
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid fe_sec_voltage \n " ) ;
2014-08-22 04:06:13 +04:00
ret = - EINVAL ;
goto err ;
2014-08-11 08:22:45 +04:00
}
2014-08-22 04:06:13 +04:00
/* output pin polarity */
2015-04-17 03:36:00 +03:00
voltage_sel ^ = dev - > cfg - > lnb_hv_pol ;
voltage_dis ^ = dev - > cfg - > lnb_en_pol ;
2014-08-22 04:06:13 +04:00
2015-04-17 04:43:52 +03:00
utmp = voltage_dis < < 1 | voltage_sel < < 0 ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa2 , 0x03 , utmp ) ;
2014-08-22 04:06:13 +04:00
if ( ret )
goto err ;
2014-08-11 08:22:45 +04:00
return 0 ;
2014-08-22 04:06:13 +04:00
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2014-08-22 04:06:13 +04:00
return ret ;
2014-08-11 08:22:45 +04:00
}
2013-02-25 15:39:16 +04:00
static int m88ds3103_diseqc_send_master_cmd ( struct dvb_frontend * fe ,
struct dvb_diseqc_master_cmd * diseqc_cmd )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2015-04-14 18:56:24 +03:00
int ret ;
2015-04-17 04:43:52 +03:00
unsigned int utmp ;
2015-04-14 18:56:24 +03:00
unsigned long timeout ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " msg=%*ph \n " ,
diseqc_cmd - > msg_len , diseqc_cmd - > msg ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm ) {
2013-02-25 15:39:16 +04:00
ret = - EAGAIN ;
goto err ;
}
if ( diseqc_cmd - > msg_len < 3 | | diseqc_cmd - > msg_len > 6 ) {
ret = - EINVAL ;
goto err ;
}
2015-04-17 04:43:52 +03:00
utmp = dev - > cfg - > envelope_mode < < 5 ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa2 , 0xe0 , utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_bulk_write ( dev - > regmap , 0xa3 , diseqc_cmd - > msg ,
2013-02-25 15:39:16 +04:00
diseqc_cmd - > msg_len ) ;
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xa1 ,
2013-02-25 15:39:16 +04:00
( diseqc_cmd - > msg_len - 1 ) < < 3 | 0x07 ) ;
if ( ret )
goto err ;
/* wait DiSEqC TX ready */
2015-04-14 18:56:24 +03:00
# define SEND_MASTER_CMD_TIMEOUT 120
timeout = jiffies + msecs_to_jiffies ( SEND_MASTER_CMD_TIMEOUT ) ;
2016-06-30 02:39:45 +03:00
/* DiSEqC message period is 13.5 ms per byte */
utmp = diseqc_cmd - > msg_len * 13500 ;
usleep_range ( utmp - 4000 , utmp ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
for ( utmp = 1 ; ! time_after ( jiffies , timeout ) & & utmp ; ) {
ret = regmap_read ( dev - > regmap , 0xa1 , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
utmp = ( utmp > > 6 ) & 0x1 ;
2013-02-25 15:39:16 +04:00
}
2015-04-17 04:43:52 +03:00
if ( utmp = = 0 ) {
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " diseqc tx took %u ms \n " ,
2015-04-14 18:56:24 +03:00
jiffies_to_msecs ( jiffies ) -
( jiffies_to_msecs ( timeout ) - SEND_MASTER_CMD_TIMEOUT ) ) ;
} else {
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " diseqc tx timeout \n " ) ;
2013-02-25 15:39:16 +04:00
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa1 , 0xc0 , 0x40 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
}
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa2 , 0xc0 , 0x80 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
if ( utmp = = 1 ) {
2013-02-25 15:39:16 +04:00
ret = - ETIMEDOUT ;
goto err ;
}
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
static int m88ds3103_diseqc_send_burst ( struct dvb_frontend * fe ,
2015-06-07 20:53:52 +03:00
enum fe_sec_mini_cmd fe_sec_mini_cmd )
2013-02-25 15:39:16 +04:00
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2015-04-14 18:56:24 +03:00
int ret ;
2015-04-17 04:43:52 +03:00
unsigned int utmp , burst ;
2015-04-14 18:56:24 +03:00
unsigned long timeout ;
2014-08-22 04:38:29 +04:00
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " fe_sec_mini_cmd=%d \n " , fe_sec_mini_cmd ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 03:36:00 +03:00
if ( ! dev - > warm ) {
2013-02-25 15:39:16 +04:00
ret = - EAGAIN ;
goto err ;
}
2015-04-17 04:43:52 +03:00
utmp = dev - > cfg - > envelope_mode < < 5 ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa2 , 0xe0 , utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
switch ( fe_sec_mini_cmd ) {
case SEC_MINI_A :
burst = 0x02 ;
break ;
case SEC_MINI_B :
burst = 0x01 ;
break ;
default :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " invalid fe_sec_mini_cmd \n " ) ;
2013-02-25 15:39:16 +04:00
ret = - EINVAL ;
goto err ;
}
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0xa1 , burst ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
/* wait DiSEqC TX ready */
2015-04-14 18:56:24 +03:00
# define SEND_BURST_TIMEOUT 40
timeout = jiffies + msecs_to_jiffies ( SEND_BURST_TIMEOUT ) ;
/* DiSEqC ToneBurst period is 12.5 ms */
usleep_range ( 8500 , 12500 ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
for ( utmp = 1 ; ! time_after ( jiffies , timeout ) & & utmp ; ) {
ret = regmap_read ( dev - > regmap , 0xa1 , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
utmp = ( utmp > > 6 ) & 0x1 ;
2013-02-25 15:39:16 +04:00
}
2015-04-17 04:43:52 +03:00
if ( utmp = = 0 ) {
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " diseqc tx took %u ms \n " ,
2015-04-14 18:56:24 +03:00
jiffies_to_msecs ( jiffies ) -
( jiffies_to_msecs ( timeout ) - SEND_BURST_TIMEOUT ) ) ;
} else {
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " diseqc tx timeout \n " ) ;
2015-04-14 18:56:24 +03:00
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa1 , 0xc0 , 0x40 ) ;
2015-04-14 18:56:24 +03:00
if ( ret )
goto err ;
}
2013-02-25 15:39:16 +04:00
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0xa2 , 0xc0 , 0x80 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
goto err ;
2015-04-17 04:43:52 +03:00
if ( utmp = = 1 ) {
2013-02-25 15:39:16 +04:00
ret = - ETIMEDOUT ;
goto err ;
}
return 0 ;
err :
2015-04-17 03:36:00 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-02-25 15:39:16 +04:00
return ret ;
}
static int m88ds3103_get_tune_settings ( struct dvb_frontend * fe ,
struct dvb_frontend_tune_settings * s )
{
s - > min_delay_ms = 3000 ;
return 0 ;
}
2013-11-20 03:32:42 +04:00
static void m88ds3103_release ( struct dvb_frontend * fe )
2013-02-25 15:39:16 +04:00
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = fe - > demodulator_priv ;
struct i2c_client * client = dev - > client ;
2014-08-22 04:38:29 +04:00
2015-04-17 02:04:55 +03:00
i2c_unregister_device ( client ) ;
2013-02-25 15:39:16 +04:00
}
2016-04-20 09:41:02 +03:00
static int m88ds3103_select ( struct i2c_mux_core * muxc , u32 chan )
2013-02-25 15:39:16 +04:00
{
2016-04-20 09:41:02 +03:00
struct m88ds3103_dev * dev = i2c_mux_priv ( muxc ) ;
2015-04-17 03:36:00 +03:00
struct i2c_client * client = dev - > client ;
2013-02-25 15:39:16 +04:00
int ret ;
2015-04-17 04:43:52 +03:00
struct i2c_msg msg = {
. addr = client - > addr ,
. flags = 0 ,
. len = 2 ,
. buf = " \x03 \x11 " ,
2013-02-25 15:39:16 +04:00
} ;
2015-04-17 04:43:52 +03:00
/* Open tuner I2C repeater for 1 xfer, closes automatically */
ret = __i2c_transfer ( client - > adapter , & msg , 1 ) ;
2013-02-25 15:39:16 +04:00
if ( ret ! = 1 ) {
2015-04-17 03:36:00 +03:00
dev_warn ( & client - > dev , " i2c wr failed=%d \n " , ret ) ;
2013-11-20 03:32:42 +04:00
if ( ret > = 0 )
ret = - EREMOTEIO ;
return ret ;
}
2013-02-25 15:39:16 +04:00
2013-11-20 03:32:42 +04:00
return 0 ;
2013-02-25 15:39:16 +04:00
}
2015-04-17 02:04:55 +03:00
/*
* XXX : That is wrapper to m88ds3103_probe ( ) via driver core in order to provide
* proper I2C client for legacy media attach binding .
* New users must use I2C client binding directly !
*/
2013-02-25 15:39:16 +04:00
struct dvb_frontend * m88ds3103_attach ( const struct m88ds3103_config * cfg ,
2018-02-10 14:14:10 +03:00
struct i2c_adapter * i2c ,
struct i2c_adapter * * tuner_i2c_adapter )
2013-02-25 15:39:16 +04:00
{
2015-04-17 02:04:55 +03:00
struct i2c_client * client ;
struct i2c_board_info board_info ;
2018-02-10 14:14:10 +03:00
struct m88ds3103_platform_data pdata = { } ;
2015-04-17 02:04:55 +03:00
pdata . clk = cfg - > clock ;
pdata . i2c_wr_max = cfg - > i2c_wr_max ;
pdata . ts_mode = cfg - > ts_mode ;
pdata . ts_clk = cfg - > ts_clk ;
pdata . ts_clk_pol = cfg - > ts_clk_pol ;
pdata . spec_inv = cfg - > spec_inv ;
pdata . agc = cfg - > agc ;
pdata . agc_inv = cfg - > agc_inv ;
pdata . clk_out = cfg - > clock_out ;
pdata . envelope_mode = cfg - > envelope_mode ;
pdata . lnb_hv_pol = cfg - > lnb_hv_pol ;
pdata . lnb_en_pol = cfg - > lnb_en_pol ;
pdata . attach_in_use = true ;
memset ( & board_info , 0 , sizeof ( board_info ) ) ;
2018-09-10 15:19:14 +03:00
strscpy ( board_info . type , " m88ds3103 " , I2C_NAME_SIZE ) ;
2015-04-17 02:04:55 +03:00
board_info . addr = cfg - > i2c_addr ;
board_info . platform_data = & pdata ;
2019-12-16 18:51:31 +03:00
client = i2c_new_client_device ( i2c , & board_info ) ;
if ( ! i2c_client_has_driver ( client ) )
2015-04-17 02:04:55 +03:00
return NULL ;
* tuner_i2c_adapter = pdata . get_i2c_adapter ( client ) ;
return pdata . get_dvb_frontend ( client ) ;
}
EXPORT_SYMBOL ( m88ds3103_attach ) ;
2016-08-10 00:32:21 +03:00
static const struct dvb_frontend_ops m88ds3103_ops = {
2015-04-17 03:36:00 +03:00
. delsys = { SYS_DVBS , SYS_DVBS2 } ,
2015-04-17 02:04:55 +03:00
. info = {
2015-04-17 03:36:00 +03:00
. name = " Montage Technology M88DS3103 " ,
2018-07-06 01:59:36 +03:00
. frequency_min_hz = 950 * MHz ,
. frequency_max_hz = 2150 * MHz ,
. frequency_tolerance_hz = 5 * MHz ,
2015-04-17 02:04:55 +03:00
. symbol_rate_min = 1000000 ,
. symbol_rate_max = 45000000 ,
. caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 |
FE_CAN_FEC_6_7 |
FE_CAN_FEC_7_8 |
FE_CAN_FEC_8_9 |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK |
FE_CAN_RECOVER |
FE_CAN_2G_MODULATION
} ,
. release = m88ds3103_release ,
. get_tune_settings = m88ds3103_get_tune_settings ,
. init = m88ds3103_init ,
. sleep = m88ds3103_sleep ,
. set_frontend = m88ds3103_set_frontend ,
. get_frontend = m88ds3103_get_frontend ,
. read_status = m88ds3103_read_status ,
. read_snr = m88ds3103_read_snr ,
. read_ber = m88ds3103_read_ber ,
. diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd ,
. diseqc_send_burst = m88ds3103_diseqc_send_burst ,
. set_tone = m88ds3103_set_tone ,
. set_voltage = m88ds3103_set_voltage ,
} ;
static struct dvb_frontend * m88ds3103_get_dvb_frontend ( struct i2c_client * client )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = i2c_get_clientdata ( client ) ;
2015-04-17 02:04:55 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
return & dev - > fe ;
}
static struct i2c_adapter * m88ds3103_get_i2c_adapter ( struct i2c_client * client )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = i2c_get_clientdata ( client ) ;
2015-04-17 02:04:55 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2016-04-20 09:41:02 +03:00
return dev - > muxc - > adapter [ 0 ] ;
2015-04-17 02:04:55 +03:00
}
static int m88ds3103_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev ;
2015-04-17 02:04:55 +03:00
struct m88ds3103_platform_data * pdata = client - > dev . platform_data ;
2013-02-25 15:39:16 +04:00
int ret ;
2015-04-17 04:43:52 +03:00
unsigned int utmp ;
2013-02-25 15:39:16 +04:00
2015-04-17 02:04:55 +03:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev ) {
2013-02-25 15:39:16 +04:00
ret = - ENOMEM ;
goto err ;
}
2015-04-17 02:04:55 +03:00
dev - > client = client ;
dev - > config . clock = pdata - > clk ;
dev - > config . i2c_wr_max = pdata - > i2c_wr_max ;
dev - > config . ts_mode = pdata - > ts_mode ;
2016-06-30 02:39:47 +03:00
dev - > config . ts_clk = pdata - > ts_clk * 1000 ;
2015-04-17 02:04:55 +03:00
dev - > config . ts_clk_pol = pdata - > ts_clk_pol ;
dev - > config . spec_inv = pdata - > spec_inv ;
dev - > config . agc_inv = pdata - > agc_inv ;
dev - > config . clock_out = pdata - > clk_out ;
dev - > config . envelope_mode = pdata - > envelope_mode ;
dev - > config . agc = pdata - > agc ;
dev - > config . lnb_hv_pol = pdata - > lnb_hv_pol ;
dev - > config . lnb_en_pol = pdata - > lnb_en_pol ;
dev - > cfg = & dev - > config ;
2015-04-17 04:43:52 +03:00
/* create regmap */
dev - > regmap_config . reg_bits = 8 ,
dev - > regmap_config . val_bits = 8 ,
dev - > regmap_config . lock_arg = dev ,
dev - > regmap = devm_regmap_init_i2c ( client , & dev - > regmap_config ) ;
if ( IS_ERR ( dev - > regmap ) ) {
ret = PTR_ERR ( dev - > regmap ) ;
goto err_kfree ;
}
2013-02-25 15:39:16 +04:00
2014-10-30 11:01:14 +03:00
/* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */
2015-04-17 04:43:52 +03:00
ret = regmap_read ( dev - > regmap , 0x00 , & utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
dev - > chip_id = utmp > > 1 ;
2020-02-02 00:48:24 +03:00
dev - > chiptype = ( u8 ) id - > driver_data ;
2015-04-17 04:43:52 +03:00
dev_dbg ( & client - > dev , " chip_id=%02x \n " , dev - > chip_id ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 04:43:52 +03:00
switch ( dev - > chip_id ) {
2014-10-30 11:01:14 +03:00
case M88RS6000_CHIP_ID :
case M88DS3103_CHIP_ID :
2013-02-25 15:39:16 +04:00
break ;
default :
2018-02-10 14:14:10 +03:00
ret = - ENODEV ;
dev_err ( & client - > dev , " Unknown device. Chip_id=%02x \n " , dev - > chip_id ) ;
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2013-02-25 15:39:16 +04:00
}
2015-04-17 02:04:55 +03:00
switch ( dev - > cfg - > clock_out ) {
2013-02-25 15:39:16 +04:00
case M88DS3103_CLOCK_OUT_DISABLED :
2015-04-17 04:43:52 +03:00
utmp = 0x80 ;
2013-02-25 15:39:16 +04:00
break ;
case M88DS3103_CLOCK_OUT_ENABLED :
2015-04-17 04:43:52 +03:00
utmp = 0x00 ;
2013-02-25 15:39:16 +04:00
break ;
case M88DS3103_CLOCK_OUT_ENABLED_DIV2 :
2015-04-17 04:43:52 +03:00
utmp = 0x10 ;
2013-02-25 15:39:16 +04:00
break ;
default :
2015-06-02 13:20:00 +03:00
ret = - EINVAL ;
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2013-02-25 15:39:16 +04:00
}
2016-06-30 02:39:46 +03:00
if ( ! pdata - > ts_clk ) {
ret = - EINVAL ;
goto err_kfree ;
}
2014-10-30 11:01:14 +03:00
/* 0x29 register is defined differently for m88rs6000. */
/* set internal tuner address to 0x21 */
2015-04-17 04:43:52 +03:00
if ( dev - > chip_id = = M88RS6000_CHIP_ID )
utmp = 0x00 ;
2014-10-30 11:01:14 +03:00
2015-04-17 04:43:52 +03:00
ret = regmap_write ( dev - > regmap , 0x29 , utmp ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2013-02-25 15:39:16 +04:00
/* sleep */
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x08 , 0x01 , 0x00 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x04 , 0x01 , 0x01 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2015-10-04 00:35:14 +03:00
ret = m88ds3103_update_bits ( dev , 0x23 , 0x10 , 0x10 ) ;
2013-02-25 15:39:16 +04:00
if ( ret )
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2013-02-25 15:39:16 +04:00
2013-11-20 03:32:42 +04:00
/* create mux i2c adapter for tuner */
2016-04-20 09:41:02 +03:00
dev - > muxc = i2c_mux_alloc ( client - > adapter , & client - > dev , 1 , 0 , 0 ,
m88ds3103_select , NULL ) ;
if ( ! dev - > muxc ) {
2015-06-02 13:20:00 +03:00
ret = - ENOMEM ;
2015-04-17 02:04:55 +03:00
goto err_kfree ;
2015-06-02 13:20:00 +03:00
}
2016-04-20 09:41:02 +03:00
dev - > muxc - > priv = dev ;
ret = i2c_mux_add_adapter ( dev - > muxc , 0 , 0 , 0 ) ;
if ( ret )
goto err_kfree ;
2013-11-20 03:32:42 +04:00
2013-02-25 15:39:16 +04:00
/* create dvb_frontend */
2015-04-17 02:04:55 +03:00
memcpy ( & dev - > fe . ops , & m88ds3103_ops , sizeof ( struct dvb_frontend_ops ) ) ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B )
strscpy ( dev - > fe . ops . info . name , " Montage Technology M88DS3103B " ,
sizeof ( dev - > fe . ops . info . name ) ) ;
else if ( dev - > chip_id = = M88RS6000_CHIP_ID )
2018-09-10 15:19:16 +03:00
strscpy ( dev - > fe . ops . info . name , " Montage Technology M88RS6000 " ,
2015-04-17 03:36:00 +03:00
sizeof ( dev - > fe . ops . info . name ) ) ;
2015-04-17 02:04:55 +03:00
if ( ! pdata - > attach_in_use )
dev - > fe . ops . release = NULL ;
dev - > fe . demodulator_priv = dev ;
i2c_set_clientdata ( client , dev ) ;
/* setup callbacks */
pdata - > get_dvb_frontend = m88ds3103_get_dvb_frontend ;
pdata - > get_i2c_adapter = m88ds3103_get_i2c_adapter ;
2020-02-02 00:48:24 +03:00
if ( dev - > chiptype = = M88DS3103_CHIPTYPE_3103B ) {
/* enable i2c repeater for tuner */
m88ds3103_update_bits ( dev , 0x11 , 0x01 , 0x01 ) ;
/* get frontend address */
ret = regmap_read ( dev - > regmap , 0x29 , & utmp ) ;
if ( ret )
goto err_kfree ;
dev - > dt_addr = ( ( utmp & 0x80 ) = = 0 ) ? 0x42 > > 1 : 0x40 > > 1 ;
2020-04-11 17:27:29 +03:00
dev_dbg ( & client - > dev , " dt addr is 0x%02x \n " , dev - > dt_addr ) ;
2020-02-02 00:48:24 +03:00
dev - > dt_client = i2c_new_dummy_device ( client - > adapter ,
dev - > dt_addr ) ;
if ( ! dev - > dt_client ) {
ret = - ENODEV ;
goto err_kfree ;
}
}
2015-04-17 02:04:55 +03:00
return 0 ;
err_kfree :
kfree ( dev ) ;
2013-02-25 15:39:16 +04:00
err :
2015-04-17 02:04:55 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
return ret ;
2013-02-25 15:39:16 +04:00
}
2015-04-17 02:04:55 +03:00
static int m88ds3103_remove ( struct i2c_client * client )
{
2015-04-17 03:36:00 +03:00
struct m88ds3103_dev * dev = i2c_get_clientdata ( client ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 02:04:55 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-02-25 15:39:16 +04:00
2020-02-02 00:48:24 +03:00
if ( dev - > dt_client )
i2c_unregister_device ( dev - > dt_client ) ;
2016-04-20 09:41:02 +03:00
i2c_mux_del_adapters ( dev - > muxc ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 02:04:55 +03:00
kfree ( dev ) ;
return 0 ;
}
2013-02-25 15:39:16 +04:00
2015-04-17 02:04:55 +03:00
static const struct i2c_device_id m88ds3103_id_table [ ] = {
2020-02-02 00:48:24 +03:00
{ " m88ds3103 " , M88DS3103_CHIPTYPE_3103 } ,
{ " m88rs6000 " , M88DS3103_CHIPTYPE_RS6000 } ,
{ " m88ds3103b " , M88DS3103_CHIPTYPE_3103B } ,
2015-04-17 02:04:55 +03:00
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , m88ds3103_id_table ) ;
2013-02-25 15:39:16 +04:00
2015-04-17 02:04:55 +03:00
static struct i2c_driver m88ds3103_driver = {
. driver = {
. name = " m88ds3103 " ,
. suppress_bind_attrs = true ,
} ,
. probe = m88ds3103_probe ,
. remove = m88ds3103_remove ,
. id_table = m88ds3103_id_table ,
2013-02-25 15:39:16 +04:00
} ;
2015-04-17 02:04:55 +03:00
module_i2c_driver ( m88ds3103_driver ) ;
2013-02-25 15:39:16 +04:00
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
2015-04-17 03:36:00 +03:00
MODULE_DESCRIPTION ( " Montage Technology M88DS3103 DVB-S/S2 demodulator driver " ) ;
2013-02-25 15:39:16 +04:00
MODULE_LICENSE ( " GPL " ) ;
MODULE_FIRMWARE ( M88DS3103_FIRMWARE ) ;
2014-10-30 11:01:14 +03:00
MODULE_FIRMWARE ( M88RS6000_FIRMWARE ) ;
2020-02-02 00:48:24 +03:00
MODULE_FIRMWARE ( M88DS3103B_FIRMWARE ) ;