2013-11-29 23:19:50 +04:00
/*
* Panasonic MN88472 DVB - T / T2 / C demodulator driver
*
* Copyright ( C ) 2013 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 .
*/
# include "mn88472_priv.h"
2013-12-03 03:28:58 +04:00
static int mn88472_get_tune_settings ( struct dvb_frontend * fe ,
2016-05-13 18:19:19 +03:00
struct dvb_frontend_tune_settings * s )
2013-12-03 03:28:58 +04:00
{
2016-05-13 18:19:19 +03:00
s - > min_delay_ms = 1000 ;
2013-12-03 03:28:58 +04:00
return 0 ;
}
2016-05-13 18:19:19 +03:00
static int mn88472_read_status ( struct dvb_frontend * fe , enum fe_status * status )
{
struct i2c_client * client = fe - > demodulator_priv ;
struct mn88472_dev * dev = i2c_get_clientdata ( client ) ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2017-03-17 19:34:44 +03:00
int ret , i , stmp ;
unsigned int utmp , utmp1 , utmp2 ;
u8 buf [ 5 ] ;
2016-05-13 18:19:19 +03:00
if ( ! dev - > active ) {
ret = - EAGAIN ;
goto err ;
}
switch ( c - > delivery_system ) {
case SYS_DVBT :
ret = regmap_read ( dev - > regmap [ 0 ] , 0x7f , & utmp ) ;
if ( ret )
goto err ;
if ( ( utmp & 0x0f ) > = 0x09 )
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK ;
else
* status = 0 ;
break ;
case SYS_DVBT2 :
ret = regmap_read ( dev - > regmap [ 2 ] , 0x92 , & utmp ) ;
if ( ret )
goto err ;
if ( ( utmp & 0x0f ) > = 0x0d )
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK ;
else if ( ( utmp & 0x0f ) > = 0x0a )
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI ;
else if ( ( utmp & 0x0f ) > = 0x07 )
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER ;
else
* status = 0 ;
break ;
case SYS_DVBC_ANNEX_A :
ret = regmap_read ( dev - > regmap [ 1 ] , 0x84 , & utmp ) ;
if ( ret )
goto err ;
if ( ( utmp & 0x0f ) > = 0x08 )
* status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK ;
else
* status = 0 ;
break ;
default :
ret = - EINVAL ;
goto err ;
}
2017-03-17 18:43:06 +03:00
/* Signal strength */
if ( * status & FE_HAS_SIGNAL ) {
for ( i = 0 ; i < 2 ; i + + ) {
ret = regmap_bulk_read ( dev - > regmap [ 2 ] , 0x8e + i ,
& buf [ i ] , 1 ) ;
if ( ret )
goto err ;
}
utmp1 = buf [ 0 ] < < 8 | buf [ 1 ] < < 0 | buf [ 0 ] > > 2 ;
dev_dbg ( & client - > dev , " strength=%u \n " , utmp1 ) ;
c - > strength . stat [ 0 ] . scale = FE_SCALE_RELATIVE ;
c - > strength . stat [ 0 ] . uvalue = utmp1 ;
} else {
c - > strength . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
}
2017-03-17 19:34:44 +03:00
/* CNR */
if ( * status & FE_HAS_VITERBI & & c - > delivery_system = = SYS_DVBT ) {
/* DVB-T CNR */
ret = regmap_bulk_read ( dev - > regmap [ 0 ] , 0x9c , buf , 2 ) ;
if ( ret )
goto err ;
utmp = buf [ 0 ] < < 8 | buf [ 1 ] < < 0 ;
if ( utmp ) {
/* CNR[dB]: 10 * log10(65536 / value) + 2 */
/* log10(65536) = 80807124, 0.2 = 3355443 */
stmp = ( ( u64 ) 80807124 - intlog10 ( utmp ) + 3355443 )
* 10000 > > 24 ;
dev_dbg ( & client - > dev , " cnr=%d value=%u \n " , stmp , utmp ) ;
} else {
stmp = 0 ;
}
c - > cnr . stat [ 0 ] . svalue = stmp ;
c - > cnr . stat [ 0 ] . scale = FE_SCALE_DECIBEL ;
} else if ( * status & FE_HAS_VITERBI & &
c - > delivery_system = = SYS_DVBT2 ) {
/* DVB-T2 CNR */
for ( i = 0 ; i < 3 ; i + + ) {
ret = regmap_bulk_read ( dev - > regmap [ 2 ] , 0xbc + i ,
& buf [ i ] , 1 ) ;
if ( ret )
goto err ;
}
utmp = buf [ 1 ] < < 8 | buf [ 2 ] < < 0 ;
utmp1 = ( buf [ 0 ] > > 2 ) & 0x01 ; /* 0=SISO, 1=MISO */
if ( utmp ) {
if ( utmp1 ) {
/* CNR[dB]: 10 * log10(16384 / value) - 6 */
/* log10(16384) = 70706234, 0.6 = 10066330 */
stmp = ( ( u64 ) 70706234 - intlog10 ( utmp )
- 10066330 ) * 10000 > > 24 ;
dev_dbg ( & client - > dev , " cnr=%d value=%u MISO \n " ,
stmp , utmp ) ;
} else {
/* CNR[dB]: 10 * log10(65536 / value) + 2 */
/* log10(65536) = 80807124, 0.2 = 3355443 */
stmp = ( ( u64 ) 80807124 - intlog10 ( utmp )
+ 3355443 ) * 10000 > > 24 ;
dev_dbg ( & client - > dev , " cnr=%d value=%u SISO \n " ,
stmp , utmp ) ;
}
} else {
stmp = 0 ;
}
c - > cnr . stat [ 0 ] . svalue = stmp ;
c - > cnr . stat [ 0 ] . scale = FE_SCALE_DECIBEL ;
} else if ( * status & FE_HAS_VITERBI & &
c - > delivery_system = = SYS_DVBC_ANNEX_A ) {
/* DVB-C CNR */
ret = regmap_bulk_read ( dev - > regmap [ 1 ] , 0xa1 , buf , 4 ) ;
if ( ret )
goto err ;
utmp1 = buf [ 0 ] < < 8 | buf [ 1 ] < < 0 ; /* signal */
utmp2 = buf [ 2 ] < < 8 | buf [ 3 ] < < 0 ; /* noise */
if ( utmp1 & & utmp2 ) {
/* CNR[dB]: 10 * log10(8 * (signal / noise)) */
/* log10(8) = 15151336 */
stmp = ( ( u64 ) 15151336 + intlog10 ( utmp1 )
- intlog10 ( utmp2 ) ) * 10000 > > 24 ;
dev_dbg ( & client - > dev , " cnr=%d signal=%u noise=%u \n " ,
stmp , utmp1 , utmp2 ) ;
} else {
stmp = 0 ;
}
c - > cnr . stat [ 0 ] . svalue = stmp ;
c - > cnr . stat [ 0 ] . scale = FE_SCALE_DECIBEL ;
} else {
c - > cnr . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
}
2017-03-17 19:45:48 +03:00
/* PER */
if ( * status & FE_HAS_SYNC ) {
ret = regmap_bulk_read ( dev - > regmap [ 0 ] , 0xe1 , buf , 4 ) ;
if ( ret )
goto err ;
utmp1 = buf [ 0 ] < < 8 | buf [ 1 ] < < 0 ;
utmp2 = buf [ 2 ] < < 8 | buf [ 3 ] < < 0 ;
dev_dbg ( & client - > dev , " block_error=%u block_count=%u \n " ,
utmp1 , utmp2 ) ;
c - > block_error . stat [ 0 ] . scale = FE_SCALE_COUNTER ;
c - > block_error . stat [ 0 ] . uvalue + = utmp1 ;
c - > block_count . stat [ 0 ] . scale = FE_SCALE_COUNTER ;
c - > block_count . stat [ 0 ] . uvalue + = utmp2 ;
} else {
c - > block_error . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
c - > block_count . stat [ 0 ] . scale = FE_SCALE_NOT_AVAILABLE ;
}
2016-05-13 18:19:19 +03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
return ret ;
}
2014-10-26 04:23:09 +03:00
static int mn88472_set_frontend ( struct dvb_frontend * fe )
2013-11-29 23:19:50 +04:00
{
2014-10-27 05:01:07 +03:00
struct i2c_client * client = fe - > demodulator_priv ;
struct mn88472_dev * dev = i2c_get_clientdata ( client ) ;
2013-11-29 23:19:50 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2014-10-28 02:39:40 +03:00
int ret , i ;
2016-05-13 18:19:19 +03:00
unsigned int utmp ;
u32 if_frequency ;
u8 buf [ 3 ] , delivery_system_val , bandwidth_val , * bandwidth_vals_ptr ;
u8 reg_bank0_b4_val , reg_bank0_cd_val , reg_bank0_d4_val ;
u8 reg_bank0_d6_val ;
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev ,
2016-05-13 18:19:19 +03:00
" delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d \n " ,
c - > delivery_system , c - > modulation , c - > frequency ,
c - > bandwidth_hz , c - > symbol_rate , c - > inversion , c - > stream_id ) ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
if ( ! dev - > active ) {
2013-11-29 23:19:50 +04:00
ret = - EAGAIN ;
goto err ;
}
2014-10-28 02:39:40 +03:00
switch ( c - > delivery_system ) {
case SYS_DVBT :
delivery_system_val = 0x02 ;
2016-05-13 18:19:19 +03:00
reg_bank0_b4_val = 0x00 ;
reg_bank0_cd_val = 0x1f ;
reg_bank0_d4_val = 0x0a ;
reg_bank0_d6_val = 0x48 ;
2014-10-28 02:39:40 +03:00
break ;
case SYS_DVBT2 :
delivery_system_val = 0x03 ;
2016-05-13 18:19:19 +03:00
reg_bank0_b4_val = 0xf6 ;
reg_bank0_cd_val = 0x01 ;
reg_bank0_d4_val = 0x09 ;
reg_bank0_d6_val = 0x46 ;
2014-10-28 02:39:40 +03:00
break ;
case SYS_DVBC_ANNEX_A :
delivery_system_val = 0x04 ;
2016-05-13 18:19:19 +03:00
reg_bank0_b4_val = 0x00 ;
reg_bank0_cd_val = 0x17 ;
reg_bank0_d4_val = 0x09 ;
reg_bank0_d6_val = 0x48 ;
2014-10-28 02:39:40 +03:00
break ;
default :
ret = - EINVAL ;
goto err ;
}
2016-05-13 18:19:19 +03:00
switch ( c - > delivery_system ) {
case SYS_DVBT :
case SYS_DVBT2 :
switch ( c - > bandwidth_hz ) {
case 5000000 :
bandwidth_vals_ptr = " \xe5 \x99 \x9a \x1b \xa9 \x1b \xa9 " ;
bandwidth_val = 0x03 ;
break ;
case 6000000 :
bandwidth_vals_ptr = " \xbf \x55 \x55 \x15 \x6b \x15 \x6b " ;
bandwidth_val = 0x02 ;
break ;
case 7000000 :
bandwidth_vals_ptr = " \xa4 \x00 \x00 \x0f \x2c \x0f \x2c " ;
bandwidth_val = 0x01 ;
break ;
case 8000000 :
bandwidth_vals_ptr = " \x8f \x80 \x00 \x08 \xee \x08 \xee " ;
bandwidth_val = 0x00 ;
break ;
default :
ret = - EINVAL ;
goto err ;
}
break ;
case SYS_DVBC_ANNEX_A :
bandwidth_vals_ptr = NULL ;
bandwidth_val = 0x00 ;
break ;
default :
break ;
2014-10-28 02:39:40 +03:00
}
2016-05-13 18:19:19 +03:00
/* Program tuner */
2013-11-29 23:19:50 +04:00
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_if_frequency ) {
ret = fe - > ops . tuner_ops . get_if_frequency ( fe , & if_frequency ) ;
if ( ret )
goto err ;
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " get_if_frequency=%d \n " , if_frequency ) ;
2016-05-13 18:19:19 +03:00
} else {
ret = - EINVAL ;
2013-11-29 23:19:50 +04:00
goto err ;
2016-05-13 18:19:19 +03:00
}
2013-11-29 23:19:50 +04:00
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x00 , 0x66 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x01 , 0x00 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x02 , 0x01 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x03 , delivery_system_val ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2016-05-13 18:19:19 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x04 , bandwidth_val ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2016-05-13 18:19:19 +03:00
/* IF */
utmp = DIV_ROUND_CLOSEST_ULL ( ( u64 ) if_frequency * 0x1000000 , dev - > clk ) ;
buf [ 0 ] = ( utmp > > 16 ) & 0xff ;
buf [ 1 ] = ( utmp > > 8 ) & 0xff ;
buf [ 2 ] = ( utmp > > 0 ) & 0xff ;
for ( i = 0 ; i < 3 ; i + + ) {
ret = regmap_write ( dev - > regmap [ 2 ] , 0x10 + i , buf [ i ] ) ;
2014-10-28 02:39:40 +03:00
if ( ret )
goto err ;
}
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
/* Bandwidth */
if ( bandwidth_vals_ptr ) {
for ( i = 0 ; i < 7 ; i + + ) {
ret = regmap_write ( dev - > regmap [ 2 ] , 0x13 + i ,
bandwidth_vals_ptr [ i ] ) ;
if ( ret )
goto err ;
}
2014-10-28 02:39:40 +03:00
}
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
ret = regmap_write ( dev - > regmap [ 0 ] , 0xb4 , reg_bank0_b4_val ) ;
if ( ret )
goto err ;
ret = regmap_write ( dev - > regmap [ 0 ] , 0xcd , reg_bank0_cd_val ) ;
if ( ret )
goto err ;
ret = regmap_write ( dev - > regmap [ 0 ] , 0xd4 , reg_bank0_d4_val ) ;
if ( ret )
goto err ;
ret = regmap_write ( dev - > regmap [ 0 ] , 0xd6 , reg_bank0_d6_val ) ;
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
switch ( c - > delivery_system ) {
case SYS_DVBT :
ret = regmap_write ( dev - > regmap [ 0 ] , 0x07 , 0x26 ) ;
2016-05-13 18:19:19 +03:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 0 ] , 0x00 , 0xba ) ;
2016-05-13 18:19:19 +03:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 0 ] , 0x01 , 0x13 ) ;
if ( ret )
goto err ;
break ;
case SYS_DVBT2 :
ret = regmap_write ( dev - > regmap [ 2 ] , 0x2b , 0x13 ) ;
2016-05-13 18:19:19 +03:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x4f , 0x05 ) ;
2016-05-13 18:19:19 +03:00
if ( ret )
goto err ;
2014-10-28 02:39:40 +03:00
ret = regmap_write ( dev - > regmap [ 1 ] , 0xf6 , 0x05 ) ;
if ( ret )
goto err ;
2017-07-30 15:34:48 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x32 ,
( c - > stream_id = = NO_STREAM_ID_FILTER ) ? 0 :
c - > stream_id ) ;
2014-10-28 02:39:40 +03:00
if ( ret )
goto err ;
break ;
2016-05-13 18:19:19 +03:00
case SYS_DVBC_ANNEX_A :
2014-12-06 03:25:33 +03:00
break ;
default :
break ;
}
2014-11-27 00:51:47 +03:00
2016-05-13 18:19:19 +03:00
/* Reset FSM */
2014-10-27 05:26:04 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0xf8 , 0x9f ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
return 0 ;
err :
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-11-29 23:19:50 +04:00
return ret ;
}
2014-10-26 04:23:09 +03:00
static int mn88472_init ( struct dvb_frontend * fe )
2013-11-29 23:19:50 +04:00
{
2014-10-27 05:01:07 +03:00
struct i2c_client * client = fe - > demodulator_priv ;
struct mn88472_dev * dev = i2c_get_clientdata ( client ) ;
2016-05-13 18:19:19 +03:00
int ret , len , rem ;
unsigned int utmp ;
const struct firmware * firmware ;
const char * name = MN88472_FIRMWARE ;
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
/* Power up */
2014-10-27 05:26:04 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x05 , 0x00 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2016-05-13 18:19:19 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x0b , 0x00 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2016-05-13 18:19:19 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x0c , 0x00 ) ;
2015-03-16 01:57:54 +03:00
if ( ret )
goto err ;
2016-05-13 18:19:19 +03:00
/* Check if firmware is already running */
ret = regmap_read ( dev - > regmap [ 0 ] , 0xf5 , & utmp ) ;
if ( ret )
goto err ;
if ( ! ( utmp & 0x01 ) )
goto warm ;
2015-03-16 01:57:54 +03:00
2016-05-13 18:19:19 +03:00
ret = request_firmware ( & firmware , name , & client - > dev ) ;
2013-11-29 23:19:50 +04:00
if ( ret ) {
2016-05-13 18:19:19 +03:00
dev_err ( & client - > dev , " firmware file '%s' not found \n " , name ) ;
2013-11-29 23:19:50 +04:00
goto err ;
}
2016-05-13 18:19:19 +03:00
dev_info ( & client - > dev , " downloading firmware from file '%s' \n " , name ) ;
2013-11-29 23:19:50 +04:00
2014-10-27 05:26:04 +03:00
ret = regmap_write ( dev - > regmap [ 0 ] , 0xf5 , 0x03 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
2016-05-13 18:19:19 +03:00
goto err_release_firmware ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
for ( rem = firmware - > size ; rem > 0 ; rem - = ( dev - > i2c_write_max - 1 ) ) {
len = min ( dev - > i2c_write_max - 1 , rem ) ;
2014-10-27 05:26:04 +03:00
ret = regmap_bulk_write ( dev - > regmap [ 0 ] , 0xf6 ,
2016-05-13 18:19:19 +03:00
& firmware - > data [ firmware - > size - rem ] ,
len ) ;
2013-11-29 23:19:50 +04:00
if ( ret ) {
2016-05-13 18:19:19 +03:00
dev_err ( & client - > dev , " firmware download failed %d \n " ,
ret ) ;
goto err_release_firmware ;
2013-11-29 23:19:50 +04:00
}
}
2016-05-13 18:19:19 +03:00
/* Parity check of firmware */
ret = regmap_read ( dev - > regmap [ 0 ] , 0xf8 , & utmp ) ;
if ( ret )
goto err_release_firmware ;
if ( utmp & 0x10 ) {
ret = - EINVAL ;
dev_err ( & client - > dev , " firmware did not run \n " ) ;
goto err_release_firmware ;
2015-03-16 01:57:51 +03:00
}
2014-10-27 05:26:04 +03:00
ret = regmap_write ( dev - > regmap [ 0 ] , 0xf5 , 0x00 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
2016-05-13 18:19:19 +03:00
goto err_release_firmware ;
release_firmware ( firmware ) ;
warm :
/* TS config */
switch ( dev - > ts_mode ) {
case SERIAL_TS_MODE :
utmp = 0x1d ;
break ;
case PARALLEL_TS_MODE :
utmp = 0x00 ;
break ;
default :
ret = - EINVAL ;
goto err ;
}
ret = regmap_write ( dev - > regmap [ 2 ] , 0x08 , utmp ) ;
if ( ret )
goto err ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
switch ( dev - > ts_clk ) {
case VARIABLE_TS_CLOCK :
utmp = 0xe3 ;
break ;
case FIXED_TS_CLOCK :
utmp = 0xe1 ;
break ;
default :
ret = - EINVAL ;
goto err ;
}
ret = regmap_write ( dev - > regmap [ 0 ] , 0xd9 , utmp ) ;
if ( ret )
goto err ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
dev - > active = true ;
2013-11-29 23:19:50 +04:00
return 0 ;
2016-05-13 18:19:19 +03:00
err_release_firmware :
release_firmware ( firmware ) ;
2015-02-01 21:34:37 +03:00
err :
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-11-29 23:19:50 +04:00
return ret ;
}
2014-10-26 04:23:09 +03:00
static int mn88472_sleep ( struct dvb_frontend * fe )
2013-11-29 23:19:50 +04:00
{
2014-10-27 05:01:07 +03:00
struct i2c_client * client = fe - > demodulator_priv ;
struct mn88472_dev * dev = i2c_get_clientdata ( client ) ;
2013-11-29 23:19:50 +04:00
int ret ;
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
/* Power down */
ret = regmap_write ( dev - > regmap [ 2 ] , 0x0c , 0x30 ) ;
if ( ret )
goto err ;
2014-10-27 05:26:04 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x0b , 0x30 ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
2014-10-27 05:26:04 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x05 , 0x3e ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
goto err ;
return 0 ;
err :
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-11-29 23:19:50 +04:00
return ret ;
}
2016-08-10 00:32:21 +03:00
static const struct dvb_frontend_ops mn88472_ops = {
2014-10-28 02:39:40 +03:00
. delsys = { SYS_DVBT , SYS_DVBT2 , SYS_DVBC_ANNEX_A } ,
2014-10-27 05:01:07 +03:00
. info = {
. name = " Panasonic MN88472 " ,
2015-03-17 01:01:53 +03:00
. symbol_rate_min = 1000000 ,
. symbol_rate_max = 7200000 ,
2014-10-27 05:01:07 +03:00
. 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 |
FE_CAN_FEC_AUTO |
FE_CAN_QPSK |
FE_CAN_QAM_16 |
FE_CAN_QAM_32 |
FE_CAN_QAM_64 |
FE_CAN_QAM_128 |
FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO |
FE_CAN_MUTE_TS |
FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM
} ,
2014-10-26 04:58:18 +03:00
2014-10-27 05:01:07 +03:00
. get_tune_settings = mn88472_get_tune_settings ,
. init = mn88472_init ,
. sleep = mn88472_sleep ,
. set_frontend = mn88472_set_frontend ,
. read_status = mn88472_read_status ,
} ;
2013-11-29 23:19:50 +04:00
2016-05-13 18:19:19 +03:00
static struct dvb_frontend * mn88472_get_dvb_frontend ( struct i2c_client * client )
{
struct mn88472_dev * dev = i2c_get_clientdata ( client ) ;
dev_dbg ( & client - > dev , " \n " ) ;
return & dev - > fe ;
}
2014-10-27 05:01:07 +03:00
static int mn88472_probe ( struct i2c_client * client ,
2016-05-13 18:19:19 +03:00
const struct i2c_device_id * id )
2013-11-29 23:19:50 +04:00
{
2016-05-13 18:19:19 +03:00
struct mn88472_config * pdata = client - > dev . platform_data ;
2014-10-26 04:58:18 +03:00
struct mn88472_dev * dev ;
2017-03-17 18:43:06 +03:00
struct dtv_frontend_properties * c ;
2014-10-27 05:01:07 +03:00
int ret ;
2014-10-27 05:26:04 +03:00
unsigned int utmp ;
static const struct regmap_config regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2013-11-29 23:19:50 +04:00
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2014-10-26 04:58:18 +03:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
2016-02-27 15:39:22 +03:00
if ( ! dev ) {
2013-11-29 23:19:50 +04:00
ret = - ENOMEM ;
goto err ;
}
2016-05-13 18:19:19 +03:00
dev - > i2c_write_max = pdata - > i2c_wr_max ? pdata - > i2c_wr_max : ~ 0 ;
dev - > clk = pdata - > xtal ;
dev - > ts_mode = pdata - > ts_mode ;
dev - > ts_clk = pdata - > ts_clock ;
2014-10-27 05:26:04 +03:00
dev - > client [ 0 ] = client ;
dev - > regmap [ 0 ] = regmap_init_i2c ( dev - > client [ 0 ] , & regmap_config ) ;
if ( IS_ERR ( dev - > regmap [ 0 ] ) ) {
ret = PTR_ERR ( dev - > regmap [ 0 ] ) ;
goto err_kfree ;
}
2013-11-29 23:19:50 +04:00
2014-10-27 05:01:07 +03:00
/*
2016-05-13 18:19:19 +03:00
* Chip has three I2C addresses for different register banks . Used
2014-10-27 05:01:07 +03:00
* addresses are 0x18 , 0x1a and 0x1c . We register two dummy clients ,
2016-05-13 18:19:19 +03:00
* 0x1a and 0x1c , in order to get own I2C client for each register bank .
*
* Also , register bank 2 do not support sequential I / O . Only single
* register write or read is allowed to that bank .
2014-10-27 05:01:07 +03:00
*/
dev - > client [ 1 ] = i2c_new_dummy ( client - > adapter , 0x1a ) ;
2016-02-27 15:39:22 +03:00
if ( ! dev - > client [ 1 ] ) {
2014-10-27 05:01:07 +03:00
ret = - ENODEV ;
dev_err ( & client - > dev , " I2C registration failed \n " ) ;
if ( ret )
2014-10-27 05:26:04 +03:00
goto err_regmap_0_regmap_exit ;
}
dev - > regmap [ 1 ] = regmap_init_i2c ( dev - > client [ 1 ] , & regmap_config ) ;
if ( IS_ERR ( dev - > regmap [ 1 ] ) ) {
ret = PTR_ERR ( dev - > regmap [ 1 ] ) ;
goto err_client_1_i2c_unregister_device ;
2014-10-27 05:01:07 +03:00
}
i2c_set_clientdata ( dev - > client [ 1 ] , dev ) ;
dev - > client [ 2 ] = i2c_new_dummy ( client - > adapter , 0x1c ) ;
2016-02-27 15:39:22 +03:00
if ( ! dev - > client [ 2 ] ) {
2014-10-27 05:01:07 +03:00
ret = - ENODEV ;
dev_err ( & client - > dev , " 2nd I2C registration failed \n " ) ;
if ( ret )
2014-10-27 05:26:04 +03:00
goto err_regmap_1_regmap_exit ;
}
dev - > regmap [ 2 ] = regmap_init_i2c ( dev - > client [ 2 ] , & regmap_config ) ;
if ( IS_ERR ( dev - > regmap [ 2 ] ) ) {
ret = PTR_ERR ( dev - > regmap [ 2 ] ) ;
goto err_client_2_i2c_unregister_device ;
2014-10-27 05:01:07 +03:00
}
i2c_set_clientdata ( dev - > client [ 2 ] , dev ) ;
2013-11-29 23:19:50 +04:00
2016-12-01 03:08:27 +03:00
/* Check demod answers with correct chip id */
ret = regmap_read ( dev - > regmap [ 2 ] , 0xff , & utmp ) ;
if ( ret )
goto err_regmap_2_regmap_exit ;
dev_dbg ( & client - > dev , " chip id=%02x \n " , utmp ) ;
if ( utmp ! = 0x02 ) {
ret = - ENODEV ;
goto err_regmap_2_regmap_exit ;
}
2016-05-13 18:19:19 +03:00
/* Sleep because chip is active by default */
ret = regmap_write ( dev - > regmap [ 2 ] , 0x05 , 0x3e ) ;
if ( ret )
goto err_regmap_2_regmap_exit ;
/* Create dvb frontend */
2014-10-26 04:58:18 +03:00
memcpy ( & dev - > fe . ops , & mn88472_ops , sizeof ( struct dvb_frontend_ops ) ) ;
2014-10-27 05:01:07 +03:00
dev - > fe . demodulator_priv = client ;
2016-05-13 18:19:19 +03:00
* pdata - > fe = & dev - > fe ;
2014-10-27 05:01:07 +03:00
i2c_set_clientdata ( client , dev ) ;
2013-11-29 23:19:50 +04:00
2017-03-17 18:43:06 +03:00
/* Init stats to indicate which stats are supported */
c = & dev - > fe . dtv_property_cache ;
c - > strength . len = 1 ;
2017-03-17 19:34:44 +03:00
c - > cnr . len = 1 ;
2017-03-17 19:45:48 +03:00
c - > block_error . len = 1 ;
c - > block_count . len = 1 ;
2017-03-17 18:43:06 +03:00
2016-05-13 18:19:19 +03:00
/* Setup callbacks */
pdata - > get_dvb_frontend = mn88472_get_dvb_frontend ;
2014-10-27 05:01:07 +03:00
2016-05-13 18:19:19 +03:00
dev_info ( & client - > dev , " Panasonic MN88472 successfully identified \n " ) ;
return 0 ;
err_regmap_2_regmap_exit :
regmap_exit ( dev - > regmap [ 2 ] ) ;
2014-10-27 05:26:04 +03:00
err_client_2_i2c_unregister_device :
i2c_unregister_device ( dev - > client [ 2 ] ) ;
err_regmap_1_regmap_exit :
regmap_exit ( dev - > regmap [ 1 ] ) ;
2014-10-27 05:01:07 +03:00
err_client_1_i2c_unregister_device :
i2c_unregister_device ( dev - > client [ 1 ] ) ;
2014-10-27 05:26:04 +03:00
err_regmap_0_regmap_exit :
regmap_exit ( dev - > regmap [ 0 ] ) ;
2014-10-27 05:01:07 +03:00
err_kfree :
2014-10-26 04:58:18 +03:00
kfree ( dev ) ;
2014-10-27 05:01:07 +03:00
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
return ret ;
2013-11-29 23:19:50 +04:00
}
2014-10-27 05:01:07 +03:00
static int mn88472_remove ( struct i2c_client * client )
{
struct mn88472_dev * dev = i2c_get_clientdata ( client ) ;
2013-11-29 23:19:50 +04:00
2014-10-27 05:01:07 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2013-11-29 23:19:50 +04:00
2014-10-27 05:26:04 +03:00
regmap_exit ( dev - > regmap [ 2 ] ) ;
2014-10-27 05:01:07 +03:00
i2c_unregister_device ( dev - > client [ 2 ] ) ;
2013-12-03 03:28:58 +04:00
2014-10-27 05:26:04 +03:00
regmap_exit ( dev - > regmap [ 1 ] ) ;
2014-10-27 05:01:07 +03:00
i2c_unregister_device ( dev - > client [ 1 ] ) ;
2013-11-29 23:19:50 +04:00
2014-10-27 05:26:04 +03:00
regmap_exit ( dev - > regmap [ 0 ] ) ;
2014-10-27 05:01:07 +03:00
kfree ( dev ) ;
2013-11-29 23:19:50 +04:00
2014-10-27 05:01:07 +03:00
return 0 ;
}
static const struct i2c_device_id mn88472_id_table [ ] = {
{ " mn88472 " , 0 } ,
{ }
2013-11-29 23:19:50 +04:00
} ;
2014-10-27 05:01:07 +03:00
MODULE_DEVICE_TABLE ( i2c , mn88472_id_table ) ;
static struct i2c_driver mn88472_driver = {
. driver = {
2016-05-13 18:19:19 +03:00
. name = " mn88472 " ,
. suppress_bind_attrs = true ,
2014-10-27 05:01:07 +03:00
} ,
2016-05-13 18:19:19 +03:00
. probe = mn88472_probe ,
. remove = mn88472_remove ,
. id_table = mn88472_id_table ,
2014-10-27 05:01:07 +03:00
} ;
module_i2c_driver ( mn88472_driver ) ;
2013-11-29 23:19:50 +04:00
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
MODULE_DESCRIPTION ( " Panasonic MN88472 DVB-T/T2/C demodulator driver " ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_FIRMWARE ( MN88472_FIRMWARE ) ;