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 ;
int ret ;
unsigned int utmp ;
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 ;
}
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 ;
2016-05-13 18:19:19 +03:00
ret = regmap_write ( dev - > regmap [ 2 ] , 0x32 , 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 ;
}
2014-10-27 05:01:07 +03:00
static 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 ;
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
2016-05-13 18:19:19 +03:00
/* Check demod answers with correct chip id */
ret = regmap_read ( dev - > regmap [ 0 ] , 0xff , & utmp ) ;
2013-11-29 23:19:50 +04:00
if ( ret )
2014-10-27 05:26:04 +03:00
goto err_regmap_0_regmap_exit ;
2014-10-27 05:01:07 +03:00
2016-05-13 18:19:19 +03:00
dev_dbg ( & client - > dev , " chip id=%02x \n " , utmp ) ;
if ( utmp ! = 0x02 ) {
ret = - ENODEV ;
goto err_regmap_0_regmap_exit ;
}
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-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
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 ) ;