2011-04-07 23:27:43 +04:00
/*
* Sony CXD2820R demodulator driver
*
* Copyright ( C ) 2010 Antti Palosaari < crope @ iki . fi >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
# include "cxd2820r_priv.h"
/* write multiple registers */
static int cxd2820r_wr_regs_i2c ( struct cxd2820r_priv * priv , u8 i2c , u8 reg ,
u8 * val , int len )
{
int ret ;
u8 buf [ len + 1 ] ;
struct i2c_msg msg [ 1 ] = {
{
. addr = i2c ,
. flags = 0 ,
2013-10-04 18:01:43 +04:00
. len = len + 1 ,
2011-04-07 23:27:43 +04:00
. buf = buf ,
}
} ;
buf [ 0 ] = reg ;
memcpy ( & buf [ 1 ] , val , len ) ;
ret = i2c_transfer ( priv - > i2c , msg , 1 ) ;
if ( ret = = 1 ) {
ret = 0 ;
} else {
2012-07-19 20:10:12 +04:00
dev_warn ( & priv - > i2c - > dev , " %s: i2c wr failed=%d reg=%02x " \
" len=%d \n " , KBUILD_MODNAME , ret , reg , len ) ;
2011-04-07 23:27:43 +04:00
ret = - EREMOTEIO ;
}
return ret ;
}
/* read multiple registers */
static int cxd2820r_rd_regs_i2c ( struct cxd2820r_priv * priv , u8 i2c , u8 reg ,
u8 * val , int len )
{
int ret ;
u8 buf [ len ] ;
struct i2c_msg msg [ 2 ] = {
{
. addr = i2c ,
. flags = 0 ,
. len = 1 ,
. buf = & reg ,
} , {
. addr = i2c ,
. flags = I2C_M_RD ,
2013-10-04 18:01:43 +04:00
. len = len ,
2011-04-07 23:27:43 +04:00
. buf = buf ,
}
} ;
ret = i2c_transfer ( priv - > i2c , msg , 2 ) ;
if ( ret = = 2 ) {
memcpy ( val , buf , len ) ;
ret = 0 ;
} else {
2012-07-19 20:10:12 +04:00
dev_warn ( & priv - > i2c - > dev , " %s: i2c rd failed=%d reg=%02x " \
" len=%d \n " , KBUILD_MODNAME , ret , reg , len ) ;
2011-04-07 23:27:43 +04:00
ret = - EREMOTEIO ;
}
return ret ;
}
/* write multiple registers */
2011-05-03 01:19:13 +04:00
int cxd2820r_wr_regs ( struct cxd2820r_priv * priv , u32 reginfo , u8 * val ,
2011-04-07 23:27:43 +04:00
int len )
{
int ret ;
u8 i2c_addr ;
u8 reg = ( reginfo > > 0 ) & 0xff ;
u8 bank = ( reginfo > > 8 ) & 0xff ;
u8 i2c = ( reginfo > > 16 ) & 0x01 ;
/* select I2C */
if ( i2c )
i2c_addr = priv - > cfg . i2c_address | ( 1 < < 1 ) ; /* DVB-C */
else
i2c_addr = priv - > cfg . i2c_address ; /* DVB-T/T2 */
/* switch bank if needed */
if ( bank ! = priv - > bank [ i2c ] ) {
ret = cxd2820r_wr_regs_i2c ( priv , i2c_addr , 0x00 , & bank , 1 ) ;
if ( ret )
return ret ;
priv - > bank [ i2c ] = bank ;
}
return cxd2820r_wr_regs_i2c ( priv , i2c_addr , reg , val , len ) ;
}
/* read multiple registers */
2011-05-03 01:19:13 +04:00
int cxd2820r_rd_regs ( struct cxd2820r_priv * priv , u32 reginfo , u8 * val ,
2011-04-07 23:27:43 +04:00
int len )
{
int ret ;
u8 i2c_addr ;
u8 reg = ( reginfo > > 0 ) & 0xff ;
u8 bank = ( reginfo > > 8 ) & 0xff ;
u8 i2c = ( reginfo > > 16 ) & 0x01 ;
/* select I2C */
if ( i2c )
i2c_addr = priv - > cfg . i2c_address | ( 1 < < 1 ) ; /* DVB-C */
else
i2c_addr = priv - > cfg . i2c_address ; /* DVB-T/T2 */
/* switch bank if needed */
if ( bank ! = priv - > bank [ i2c ] ) {
ret = cxd2820r_wr_regs_i2c ( priv , i2c_addr , 0x00 , & bank , 1 ) ;
if ( ret )
return ret ;
priv - > bank [ i2c ] = bank ;
}
return cxd2820r_rd_regs_i2c ( priv , i2c_addr , reg , val , len ) ;
}
/* write single register */
2011-05-03 01:19:13 +04:00
int cxd2820r_wr_reg ( struct cxd2820r_priv * priv , u32 reg , u8 val )
2011-04-07 23:27:43 +04:00
{
return cxd2820r_wr_regs ( priv , reg , & val , 1 ) ;
}
/* read single register */
2011-05-03 01:19:13 +04:00
int cxd2820r_rd_reg ( struct cxd2820r_priv * priv , u32 reg , u8 * val )
2011-04-07 23:27:43 +04:00
{
return cxd2820r_rd_regs ( priv , reg , val , 1 ) ;
}
/* write single register with mask */
2011-05-03 01:19:13 +04:00
int cxd2820r_wr_reg_mask ( struct cxd2820r_priv * priv , u32 reg , u8 val ,
2011-04-07 23:27:43 +04:00
u8 mask )
{
int ret ;
u8 tmp ;
/* no need for read if whole reg is written */
if ( mask ! = 0xff ) {
ret = cxd2820r_rd_reg ( priv , reg , & tmp ) ;
if ( ret )
return ret ;
val & = mask ;
tmp & = ~ mask ;
val | = tmp ;
}
return cxd2820r_wr_reg ( priv , reg , val ) ;
}
2012-07-20 04:10:36 +04:00
int cxd2820r_gpio ( struct dvb_frontend * fe , u8 * gpio )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
int ret , i ;
2012-07-20 04:10:36 +04:00
u8 tmp0 , tmp1 ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-04-07 23:27:43 +04:00
/* update GPIOs only when needed */
if ( ! memcmp ( gpio , priv - > gpio , sizeof ( priv - > gpio ) ) )
return 0 ;
tmp0 = 0x00 ;
tmp1 = 0x00 ;
for ( i = 0 ; i < sizeof ( priv - > gpio ) ; i + + ) {
/* enable / disable */
if ( gpio [ i ] & CXD2820R_GPIO_E )
tmp0 | = ( 2 < < 6 ) > > ( 2 * i ) ;
else
tmp0 | = ( 1 < < 6 ) > > ( 2 * i ) ;
/* input / output */
if ( gpio [ i ] & CXD2820R_GPIO_I )
tmp1 | = ( 1 < < ( 3 + i ) ) ;
else
tmp1 | = ( 0 < < ( 3 + i ) ) ;
/* high / low */
if ( gpio [ i ] & CXD2820R_GPIO_H )
tmp1 | = ( 1 < < ( 0 + i ) ) ;
else
tmp1 | = ( 0 < < ( 0 + i ) ) ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: gpio i=%d %02x %02x \n " , __func__ ,
i , tmp0 , tmp1 ) ;
2011-04-07 23:27:43 +04:00
}
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: wr gpio=%02x %02x \n " , __func__ , tmp0 ,
tmp1 ) ;
2011-04-07 23:27:43 +04:00
/* write bits [7:2] */
ret = cxd2820r_wr_reg_mask ( priv , 0x00089 , tmp0 , 0xfc ) ;
if ( ret )
goto error ;
/* write bits [5:0] */
ret = cxd2820r_wr_reg_mask ( priv , 0x0008e , tmp1 , 0x3f ) ;
if ( ret )
goto error ;
memcpy ( priv - > gpio , gpio , sizeof ( priv - > gpio ) ) ;
return ret ;
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
/* 64 bit div with round closest, like DIV_ROUND_CLOSEST but 64 bit */
2011-05-03 01:19:13 +04:00
u32 cxd2820r_div_u64_round_closest ( u64 dividend , u32 divisor )
2011-04-07 23:27:43 +04:00
{
return div_u64 ( dividend + ( divisor / 2 ) , divisor ) ;
}
2011-12-31 05:22:10 +04:00
static int cxd2820r_set_frontend ( struct dvb_frontend * fe )
2011-04-07 23:27:43 +04:00
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( c - > delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_init_t ( fe ) ;
if ( ret < 0 )
goto err ;
2011-12-31 05:22:10 +04:00
ret = cxd2820r_set_frontend_t ( fe ) ;
2011-11-24 18:59:53 +04:00
if ( ret < 0 )
goto err ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_init_t ( fe ) ;
if ( ret < 0 )
goto err ;
2011-12-31 05:22:10 +04:00
ret = cxd2820r_set_frontend_t2 ( fe ) ;
2011-11-24 18:59:53 +04:00
if ( ret < 0 )
goto err ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-11-24 18:59:53 +04:00
ret = cxd2820r_init_c ( fe ) ;
if ( ret < 0 )
goto err ;
2011-12-31 05:22:10 +04:00
ret = cxd2820r_set_frontend_c ( fe ) ;
2011-11-24 18:59:53 +04:00
if ( ret < 0 )
goto err ;
break ;
default :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: error state=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
2011-11-24 18:59:53 +04:00
err :
2011-04-07 23:27:43 +04:00
return ret ;
}
static int cxd2820r_read_status ( struct dvb_frontend * fe , fe_status_t * status )
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_read_status_t ( fe , status ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_read_status_t2 ( fe , status ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_read_status_c ( fe , status ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
[media] dvb: don't require a parameter for get_frontend
Just like set_frontend, use the dvb cache properties for get_frontend.
This is more consistent, as both functions are now symetric. Also,
at the places get_frontend is called, it makes sense to update the
cache.
Most of this patch were generated by this small perl script:
while (<>) { $file .= $_; }
if ($file =~ m/\.get_frontend\s*=\s*([\d\w_]+)/) {
my $get = $1;
$file =~ s/($get)(\s*\([^\,\)]+)\,\s*struct\s+dtv_frontend_properties\s*\*\s*([_\d\w]+)\)\s*\{/\1\2)\n{\n\tstruct dtv_frontend_properties *\3 = &fe->dtv_property_cache;/g;
}
print $file;
Of course, the changes at dvb_frontend.[ch] were made by hand,
as well as the changes on a few other places, where get_frontend()
is called internally inside the driver.
On some places, get_frontend() were just a void function. Those
occurrences were removed, as the DVB core handles such cases.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2011-12-30 18:30:21 +04:00
static int cxd2820r_get_frontend ( struct dvb_frontend * fe )
2011-04-07 23:27:43 +04:00
{
2012-01-16 01:30:36 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2012-01-16 01:30:36 +04:00
if ( priv - > delivery_system = = SYS_UNDEFINED )
return 0 ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
2011-12-31 05:22:10 +04:00
ret = cxd2820r_get_frontend_t ( fe ) ;
2011-11-24 18:59:53 +04:00
break ;
case SYS_DVBT2 :
2011-12-31 05:22:10 +04:00
ret = cxd2820r_get_frontend_t2 ( fe ) ;
2011-11-24 18:59:53 +04:00
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
ret = cxd2820r_get_frontend_c ( fe ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
static int cxd2820r_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_read_ber_t ( fe , ber ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_read_ber_t2 ( fe , ber ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_read_ber_c ( fe , ber ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
static int cxd2820r_read_signal_strength ( struct dvb_frontend * fe , u16 * strength )
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_read_signal_strength_t ( fe , strength ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_read_signal_strength_t2 ( fe , strength ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_read_signal_strength_c ( fe , strength ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
static int cxd2820r_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_read_snr_t ( fe , snr ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_read_snr_t2 ( fe , snr ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_read_snr_c ( fe , snr ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
static int cxd2820r_read_ucblocks ( struct dvb_frontend * fe , u32 * ucblocks )
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_read_ucblocks_t ( fe , ucblocks ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_read_ucblocks_t2 ( fe , ucblocks ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_read_ucblocks_c ( fe , ucblocks ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
static int cxd2820r_init ( struct dvb_frontend * fe )
{
2011-11-24 18:59:53 +04:00
return 0 ;
2011-04-07 23:27:43 +04:00
}
static int cxd2820r_sleep ( struct dvb_frontend * fe )
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-04-07 23:27:43 +04:00
int ret ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_sleep_t ( fe ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_sleep_t2 ( fe ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_sleep_c ( fe ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
static int cxd2820r_get_tune_settings ( struct dvb_frontend * fe ,
2011-11-24 18:59:53 +04:00
struct dvb_frontend_tune_settings * s )
2011-04-07 23:27:43 +04:00
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2011-05-04 03:31:36 +04:00
int ret ;
2011-04-07 23:27:43 +04:00
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-11-24 18:59:53 +04:00
switch ( fe - > dtv_property_cache . delivery_system ) {
case SYS_DVBT :
ret = cxd2820r_get_tune_settings_t ( fe , s ) ;
break ;
case SYS_DVBT2 :
ret = cxd2820r_get_tune_settings_t2 ( fe , s ) ;
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2011-04-07 23:27:43 +04:00
ret = cxd2820r_get_tune_settings_c ( fe , s ) ;
2011-11-24 18:59:53 +04:00
break ;
default :
ret = - EINVAL ;
break ;
2011-04-07 23:27:43 +04:00
}
return ret ;
}
2011-12-27 01:03:12 +04:00
static enum dvbfe_search cxd2820r_search ( struct dvb_frontend * fe )
2011-05-04 03:31:36 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
int ret , i ;
fe_status_t status = 0 ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: delsys=%d \n " , __func__ ,
fe - > dtv_property_cache . delivery_system ) ;
2011-05-04 03:31:36 +04:00
/* switch between DVB-T and DVB-T2 when tune fails */
2012-01-15 22:08:30 +04:00
if ( priv - > last_tune_failed ) {
2012-01-21 02:48:28 +04:00
if ( priv - > delivery_system = = SYS_DVBT ) {
ret = cxd2820r_sleep_t ( fe ) ;
if ( ret )
goto error ;
2011-05-04 03:31:36 +04:00
c - > delivery_system = SYS_DVBT2 ;
2012-01-21 02:48:28 +04:00
} else if ( priv - > delivery_system = = SYS_DVBT2 ) {
ret = cxd2820r_sleep_t2 ( fe ) ;
if ( ret )
goto error ;
2011-05-04 03:31:36 +04:00
c - > delivery_system = SYS_DVBT ;
2012-01-21 02:48:28 +04:00
}
2011-05-04 03:31:36 +04:00
}
/* set frontend */
2011-12-31 05:22:10 +04:00
ret = cxd2820r_set_frontend ( fe ) ;
2011-05-04 03:31:36 +04:00
if ( ret )
goto error ;
/* frontend lock wait loop count */
switch ( priv - > delivery_system ) {
case SYS_DVBT :
2012-01-15 23:50:11 +04:00
case SYS_DVBC_ANNEX_A :
2011-05-04 03:31:36 +04:00
i = 20 ;
break ;
case SYS_DVBT2 :
i = 40 ;
break ;
case SYS_UNDEFINED :
default :
i = 0 ;
break ;
}
/* wait frontend lock */
for ( ; i > 0 ; i - - ) {
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: loop=%d \n " , __func__ , i ) ;
2011-05-04 03:31:36 +04:00
msleep ( 50 ) ;
ret = cxd2820r_read_status ( fe , & status ) ;
if ( ret )
goto error ;
2012-03-15 20:33:47 +04:00
if ( status & FE_HAS_LOCK )
2011-05-04 03:31:36 +04:00
break ;
}
/* check if we have a valid signal */
2012-03-15 20:33:47 +04:00
if ( status & FE_HAS_LOCK ) {
2011-05-04 03:31:36 +04:00
priv - > last_tune_failed = 0 ;
return DVBFE_ALGO_SEARCH_SUCCESS ;
} else {
priv - > last_tune_failed = 1 ;
return DVBFE_ALGO_SEARCH_AGAIN ;
}
error :
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-05-04 03:31:36 +04:00
return DVBFE_ALGO_SEARCH_ERROR ;
}
static int cxd2820r_get_frontend_algo ( struct dvb_frontend * fe )
{
return DVBFE_ALGO_CUSTOM ;
}
2011-04-07 23:27:43 +04:00
static void cxd2820r_release ( struct dvb_frontend * fe )
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2012-08-17 04:07:23 +04:00
int uninitialized_var ( ret ) ; /* silence compiler warning */
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s \n " , __func__ ) ;
2011-04-07 23:27:43 +04:00
2012-07-20 04:10:36 +04:00
# ifdef CONFIG_GPIOLIB
/* remove GPIOs */
if ( priv - > gpio_chip . label ) {
ret = gpiochip_remove ( & priv - > gpio_chip ) ;
if ( ret )
dev_err ( & priv - > i2c - > dev , " %s: gpiochip_remove() " \
" failed=%d \n " , KBUILD_MODNAME , ret ) ;
}
# endif
2011-11-24 18:59:53 +04:00
kfree ( priv ) ;
2011-04-07 23:27:43 +04:00
return ;
}
2011-08-09 14:16:21 +04:00
static int cxd2820r_i2c_gate_ctrl ( struct dvb_frontend * fe , int enable )
2011-04-07 23:27:43 +04:00
{
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: %d \n " , __func__ , enable ) ;
2011-08-09 14:16:21 +04:00
/* Bit 0 of reg 0xdb in bank 0x00 controls I2C repeater */
return cxd2820r_wr_reg_mask ( priv , 0xdb , enable ? 1 : 0 , 0x1 ) ;
2011-04-07 23:27:43 +04:00
}
2012-07-20 04:10:36 +04:00
# ifdef CONFIG_GPIOLIB
static int cxd2820r_gpio_direction_output ( struct gpio_chip * chip , unsigned nr ,
int val )
{
struct cxd2820r_priv * priv =
container_of ( chip , struct cxd2820r_priv , gpio_chip ) ;
u8 gpio [ GPIO_COUNT ] ;
dev_dbg ( & priv - > i2c - > dev , " %s: nr=%d val=%d \n " , __func__ , nr , val ) ;
memcpy ( gpio , priv - > gpio , sizeof ( gpio ) ) ;
gpio [ nr ] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | ( val < < 2 ) ;
return cxd2820r_gpio ( & priv - > fe , gpio ) ;
}
static void cxd2820r_gpio_set ( struct gpio_chip * chip , unsigned nr , int val )
{
struct cxd2820r_priv * priv =
container_of ( chip , struct cxd2820r_priv , gpio_chip ) ;
u8 gpio [ GPIO_COUNT ] ;
dev_dbg ( & priv - > i2c - > dev , " %s: nr=%d val=%d \n " , __func__ , nr , val ) ;
memcpy ( gpio , priv - > gpio , sizeof ( gpio ) ) ;
gpio [ nr ] = CXD2820R_GPIO_E | CXD2820R_GPIO_O | ( val < < 2 ) ;
( void ) cxd2820r_gpio ( & priv - > fe , gpio ) ;
return ;
}
static int cxd2820r_gpio_get ( struct gpio_chip * chip , unsigned nr )
{
struct cxd2820r_priv * priv =
container_of ( chip , struct cxd2820r_priv , gpio_chip ) ;
dev_dbg ( & priv - > i2c - > dev , " %s: nr=%d \n " , __func__ , nr ) ;
return ( priv - > gpio [ nr ] > > 2 ) & 0x01 ;
}
# endif
2011-11-24 18:59:53 +04:00
static const struct dvb_frontend_ops cxd2820r_ops = {
2011-12-31 05:22:10 +04:00
. delsys = { SYS_DVBT , SYS_DVBT2 , SYS_DVBC_ANNEX_A } ,
2011-11-24 18:59:53 +04:00
/* default: DVB-T/T2 */
. info = {
2012-01-18 20:57:33 +04:00
. name = " Sony CXD2820R " ,
2011-11-24 18:59:53 +04: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 |
2012-01-18 20:57:33 +04:00
FE_CAN_QAM_32 |
2011-11-24 18:59:53 +04:00
FE_CAN_QAM_64 |
2012-01-18 20:57:33 +04:00
FE_CAN_QAM_128 |
2011-11-24 18:59:53 +04:00
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 |
2013-04-08 06:56:46 +04:00
FE_CAN_2G_MODULATION |
FE_CAN_MULTISTREAM
2011-11-24 18:59:53 +04:00
} ,
2011-04-07 23:27:43 +04:00
2011-11-24 18:59:53 +04:00
. release = cxd2820r_release ,
. init = cxd2820r_init ,
. sleep = cxd2820r_sleep ,
2011-04-07 23:27:43 +04:00
2011-11-24 18:59:53 +04:00
. get_tune_settings = cxd2820r_get_tune_settings ,
. i2c_gate_ctrl = cxd2820r_i2c_gate_ctrl ,
2011-04-07 23:27:43 +04:00
2011-12-31 05:22:10 +04:00
. get_frontend = cxd2820r_get_frontend ,
2011-04-07 23:27:43 +04:00
2011-11-24 18:59:53 +04:00
. get_frontend_algo = cxd2820r_get_frontend_algo ,
. search = cxd2820r_search ,
2011-04-07 23:27:43 +04:00
2011-11-24 18:59:53 +04:00
. read_status = cxd2820r_read_status ,
. read_snr = cxd2820r_read_snr ,
. read_ber = cxd2820r_read_ber ,
. read_ucblocks = cxd2820r_read_ucblocks ,
. read_signal_strength = cxd2820r_read_signal_strength ,
} ;
2011-04-07 23:27:43 +04:00
2011-11-24 18:59:53 +04:00
struct dvb_frontend * cxd2820r_attach ( const struct cxd2820r_config * cfg ,
2012-07-20 04:10:36 +04:00
struct i2c_adapter * i2c , int * gpio_chip_base
)
2011-11-24 18:59:53 +04:00
{
2012-07-20 04:10:36 +04:00
struct cxd2820r_priv * priv ;
2011-11-24 18:59:53 +04:00
int ret ;
2012-10-06 01:50:12 +04:00
u8 tmp ;
2011-11-24 18:59:53 +04:00
2012-08-17 04:07:23 +04:00
priv = kzalloc ( sizeof ( struct cxd2820r_priv ) , GFP_KERNEL ) ;
2012-07-20 04:10:36 +04:00
if ( ! priv ) {
ret = - ENOMEM ;
dev_err ( & i2c - > dev , " %s: kzalloc() failed \n " ,
KBUILD_MODNAME ) ;
2011-11-24 18:59:53 +04:00
goto error ;
2012-07-20 04:10:36 +04:00
}
2011-04-07 23:27:43 +04:00
2011-11-24 18:59:53 +04:00
priv - > i2c = i2c ;
2012-08-17 04:07:23 +04:00
memcpy ( & priv - > cfg , cfg , sizeof ( struct cxd2820r_config ) ) ;
memcpy ( & priv - > fe . ops , & cxd2820r_ops , sizeof ( struct dvb_frontend_ops ) ) ;
priv - > fe . demodulator_priv = priv ;
2011-11-24 18:59:53 +04:00
priv - > bank [ 0 ] = priv - > bank [ 1 ] = 0xff ;
ret = cxd2820r_rd_reg ( priv , 0x000fd , & tmp ) ;
2012-07-19 20:10:12 +04:00
dev_dbg ( & priv - > i2c - > dev , " %s: chip id=%02x \n " , __func__ , tmp ) ;
2011-11-24 18:59:53 +04:00
if ( ret | | tmp ! = 0xe1 )
goto error ;
2012-07-20 04:10:36 +04:00
if ( gpio_chip_base ) {
2012-08-17 04:07:23 +04:00
# ifdef CONFIG_GPIOLIB
/* add GPIOs */
2012-07-20 04:10:36 +04:00
priv - > gpio_chip . label = KBUILD_MODNAME ;
priv - > gpio_chip . dev = & priv - > i2c - > dev ;
priv - > gpio_chip . owner = THIS_MODULE ;
priv - > gpio_chip . direction_output =
cxd2820r_gpio_direction_output ;
priv - > gpio_chip . set = cxd2820r_gpio_set ;
priv - > gpio_chip . get = cxd2820r_gpio_get ;
priv - > gpio_chip . base = - 1 ; /* dynamic allocation */
priv - > gpio_chip . ngpio = GPIO_COUNT ;
priv - > gpio_chip . can_sleep = 1 ;
ret = gpiochip_add ( & priv - > gpio_chip ) ;
if ( ret )
goto error ;
dev_dbg ( & priv - > i2c - > dev , " %s: gpio_chip.base=%d \n " , __func__ ,
priv - > gpio_chip . base ) ;
* gpio_chip_base = priv - > gpio_chip . base ;
2012-08-17 04:07:23 +04:00
# else
/*
* Use static GPIO configuration if GPIOLIB is undefined .
* This is fallback condition .
*/
2012-10-06 01:50:12 +04:00
u8 gpio [ GPIO_COUNT ] ;
2012-08-17 04:07:23 +04:00
gpio [ 0 ] = ( * gpio_chip_base > > 0 ) & 0x07 ;
gpio [ 1 ] = ( * gpio_chip_base > > 3 ) & 0x07 ;
gpio [ 2 ] = 0 ;
ret = cxd2820r_gpio ( & priv - > fe , gpio ) ;
if ( ret )
goto error ;
2012-07-20 04:10:36 +04:00
# endif
2012-08-17 04:07:23 +04:00
}
2012-07-20 04:10:36 +04:00
2011-11-24 18:59:53 +04:00
return & priv - > fe ;
2011-04-07 23:27:43 +04:00
error :
2012-07-20 04:10:36 +04:00
dev_dbg ( & i2c - > dev , " %s: failed=%d \n " , __func__ , ret ) ;
2011-04-07 23:27:43 +04:00
kfree ( priv ) ;
return NULL ;
}
EXPORT_SYMBOL ( cxd2820r_attach ) ;
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
MODULE_DESCRIPTION ( " Sony CXD2820R demodulator driver " ) ;
MODULE_LICENSE ( " GPL " ) ;