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"
2016-08-13 19:19:05 +03:00
/* Write register table */
int cxd2820r_wr_reg_val_mask_tab ( struct cxd2820r_priv * priv ,
const struct reg_val_mask * tab , int tab_len )
2011-04-07 23:27:43 +04:00
{
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2011-04-07 23:27:43 +04:00
int ret ;
2016-08-13 19:19:05 +03:00
unsigned int i , reg , mask , val ;
struct regmap * regmap ;
2013-11-02 12:11:47 +04:00
2016-08-13 19:19:05 +03:00
dev_dbg ( & client - > dev , " tab_len=%d \n " , tab_len ) ;
2011-04-07 23:27:43 +04:00
2016-08-13 19:19:05 +03:00
for ( i = 0 ; i < tab_len ; i + + ) {
if ( ( tab [ i ] . reg > > 16 ) & 0x1 )
regmap = priv - > regmap [ 1 ] ;
else
regmap = priv - > regmap [ 0 ] ;
2011-04-07 23:27:43 +04:00
2016-08-13 19:19:05 +03:00
reg = ( tab [ i ] . reg > > 0 ) & 0xffff ;
val = tab [ i ] . val ;
mask = tab [ i ] . mask ;
2011-04-07 23:27:43 +04:00
2016-08-13 19:19:05 +03:00
if ( mask = = 0xff )
ret = regmap_write ( regmap , reg , val ) ;
else
ret = regmap_write_bits ( regmap , reg , mask , val ) ;
2011-04-07 23:27:43 +04:00
if ( ret )
2016-08-13 19:19:05 +03:00
goto error ;
2011-04-07 23:27:43 +04:00
}
2016-08-13 19:19:05 +03:00
return 0 ;
error :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
return ret ;
2011-04-07 23:27:43 +04:00
}
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
int ret , i ;
2012-07-20 04:10:36 +04:00
u8 tmp0 , tmp1 ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > 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 ) ) ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " gpio i=%d %02x %02x \n " , i , tmp0 , tmp1 ) ;
2011-04-07 23:27:43 +04:00
}
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " wr gpio=%02x %02x \n " , tmp0 , tmp1 ) ;
2011-04-07 23:27:43 +04:00
/* write bits [7:2] */
2016-08-13 19:19:05 +03:00
ret = regmap_update_bits ( priv - > regmap [ 0 ] , 0x0089 , 0xfc , tmp0 ) ;
2011-04-07 23:27:43 +04:00
if ( ret )
goto error ;
/* write bits [5:0] */
2016-08-13 19:19:05 +03:00
ret = regmap_update_bits ( priv - > regmap [ 0 ] , 0x008e , 0x3f , tmp1 ) ;
2011-04-07 23:27:43 +04:00
if ( ret )
goto error ;
memcpy ( priv - > gpio , gpio , sizeof ( priv - > gpio ) ) ;
return ret ;
error :
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2011-04-07 23:27:43 +04:00
return ret ;
}
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2011-04-07 23:27:43 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
int ret ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
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 :
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " invalid delivery_system \n " ) ;
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 ;
}
2015-06-07 20:53:52 +03:00
static int cxd2820r_read_status ( struct dvb_frontend * fe , enum fe_status * status )
2011-04-07 23:27:43 +04:00
{
2012-07-19 20:10:12 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
int ret ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
switch ( c - > delivery_system ) {
2011-11-24 18:59:53 +04:00
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 ;
}
2016-02-04 17:58:30 +03:00
static int cxd2820r_get_frontend ( struct dvb_frontend * fe ,
struct dtv_frontend_properties * p )
2011-04-07 23:27:43 +04:00
{
2012-01-16 01:30:36 +04:00
struct cxd2820r_priv * priv = fe - > demodulator_priv ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
int ret ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-01-16 01:30:36 +04:00
if ( priv - > delivery_system = = SYS_UNDEFINED )
return 0 ;
2016-08-10 04:00:37 +03:00
switch ( c - > delivery_system ) {
2011-11-24 18:59:53 +04:00
case SYS_DVBT :
2016-02-04 17:58:30 +03:00
ret = cxd2820r_get_frontend_t ( fe , p ) ;
2011-11-24 18:59:53 +04:00
break ;
case SYS_DVBT2 :
2016-02-04 17:58:30 +03:00
ret = cxd2820r_get_frontend_t2 ( fe , p ) ;
2011-11-24 18:59:53 +04:00
break ;
2011-12-31 05:22:10 +04:00
case SYS_DVBC_ANNEX_A :
2016-02-04 17:58:30 +03:00
ret = cxd2820r_get_frontend_c ( fe , p ) ;
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-09 20:58:21 +03:00
* ber = ( priv - > post_bit_error - priv - > post_bit_error_prev_dvbv3 ) ;
priv - > post_bit_error_prev_dvbv3 = priv - > post_bit_error ;
return 0 ;
2011-04-07 23:27:43 +04:00
}
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2016-08-09 20:58:21 +03:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-09 20:58:21 +03:00
if ( c - > strength . stat [ 0 ] . scale = = FE_SCALE_RELATIVE )
* strength = c - > strength . stat [ 0 ] . uvalue ;
else
* strength = 0 ;
return 0 ;
2011-04-07 23:27:43 +04:00
}
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2016-08-09 20:58:21 +03:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-09 20:58:21 +03:00
if ( c - > cnr . stat [ 0 ] . scale = = FE_SCALE_DECIBEL )
* snr = div_s64 ( c - > cnr . stat [ 0 ] . svalue , 100 ) ;
else
* snr = 0 ;
return 0 ;
2011-04-07 23:27:43 +04:00
}
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-09 20:58:21 +03:00
* ucblocks = 0 ;
return 0 ;
2011-04-07 23:27:43 +04:00
}
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-04-07 23:27:43 +04:00
int ret ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
switch ( c - > delivery_system ) {
2011-11-24 18:59:53 +04:00
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2011-05-04 03:31:36 +04:00
int ret ;
2011-04-07 23:27:43 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > delivery_system ) ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
switch ( c - > delivery_system ) {
2011-11-24 18:59:53 +04:00
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2011-05-04 03:31:36 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
int ret , i ;
2015-06-07 20:53:52 +03:00
enum fe_status status = 0 ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " delivery_system=%d \n " , c - > 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 - - ) {
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " loop=%d \n " , 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 ) {
2014-09-03 22:22:02 +04:00
priv - > last_tune_failed = false ;
2011-05-04 03:31:36 +04:00
return DVBFE_ALGO_SEARCH_SUCCESS ;
} else {
2014-09-03 22:22:02 +04:00
priv - > last_tune_failed = true ;
2011-05-04 03:31:36 +04:00
return DVBFE_ALGO_SEARCH_AGAIN ;
}
error :
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " failed=%d \n " , 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 ;
2016-08-10 02:49:09 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
2011-04-07 23:27:43 +04:00
2016-08-10 02:49:09 +03:00
i2c_unregister_device ( client ) ;
2014-07-13 00:30:14 +04:00
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 ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2012-07-19 20:10:12 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg_ratelimited ( & client - > dev , " enable=%d \n " , enable ) ;
2011-08-09 14:16:21 +04:00
2016-08-13 19:19:05 +03:00
return regmap_update_bits ( priv - > regmap [ 0 ] , 0x00db , 0x01 , enable ? 1 : 0 ) ;
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 )
{
2015-12-09 16:46:55 +03:00
struct cxd2820r_priv * priv = gpiochip_get_data ( chip ) ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2012-07-20 04:10:36 +04:00
u8 gpio [ GPIO_COUNT ] ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " nr=%u val=%d \n " , nr , val ) ;
2012-07-20 04:10:36 +04:00
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 )
{
2015-12-09 16:46:55 +03:00
struct cxd2820r_priv * priv = gpiochip_get_data ( chip ) ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2012-07-20 04:10:36 +04:00
u8 gpio [ GPIO_COUNT ] ;
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " nr=%u val=%d \n " , nr , val ) ;
2012-07-20 04:10:36 +04:00
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 )
{
2015-12-09 16:46:55 +03:00
struct cxd2820r_priv * priv = gpiochip_get_data ( chip ) ;
2016-08-10 04:00:37 +03:00
struct i2c_client * client = priv - > client [ 0 ] ;
2012-07-20 04:10:36 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " nr=%u \n " , nr ) ;
2012-07-20 04:10:36 +04:00
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
2016-08-10 02:49:09 +03:00
/*
* XXX : That is wrapper to cxd2820r_probe ( ) via driver core in order to provide
* proper I2C client for legacy media attach binding .
* New users must use I2C client binding directly !
*/
struct dvb_frontend * cxd2820r_attach ( const struct cxd2820r_config * config ,
struct i2c_adapter * adapter ,
int * gpio_chip_base )
2011-11-24 18:59:53 +04:00
{
2016-08-10 02:49:09 +03:00
struct i2c_client * client ;
struct i2c_board_info board_info ;
struct cxd2820r_platform_data pdata ;
pdata . ts_mode = config - > ts_mode ;
pdata . ts_clk_inv = config - > ts_clock_inv ;
pdata . if_agc_polarity = config - > if_agc_polarity ;
pdata . spec_inv = config - > spec_inv ;
pdata . gpio_chip_base = & gpio_chip_base ;
pdata . attach_in_use = true ;
memset ( & board_info , 0 , sizeof ( board_info ) ) ;
strlcpy ( board_info . type , " cxd2820r " , I2C_NAME_SIZE ) ;
board_info . addr = config - > i2c_address ;
board_info . platform_data = & pdata ;
client = i2c_new_device ( adapter , & board_info ) ;
if ( ! client | | ! client - > dev . driver )
return NULL ;
return pdata . get_dvb_frontend ( client ) ;
}
EXPORT_SYMBOL ( cxd2820r_attach ) ;
static struct dvb_frontend * cxd2820r_get_dvb_frontend ( struct i2c_client * client )
{
struct cxd2820r_priv * priv = i2c_get_clientdata ( client ) ;
dev_dbg ( & client - > dev , " \n " ) ;
return & priv - > fe ;
}
static int cxd2820r_probe ( struct i2c_client * client ,
const struct i2c_device_id * id )
{
struct cxd2820r_platform_data * pdata = client - > dev . platform_data ;
2012-07-20 04:10:36 +04:00
struct cxd2820r_priv * priv ;
2016-08-10 02:49:09 +03:00
int ret , * gpio_chip_base ;
2016-08-13 19:19:05 +03:00
unsigned int utmp ;
static const struct regmap_range_cfg regmap_range_cfg0 [ ] = {
{
. range_min = 0x0000 ,
. range_max = 0x3fff ,
. selector_reg = 0x00 ,
. selector_mask = 0xff ,
. selector_shift = 0 ,
. window_start = 0x00 ,
. window_len = 0x100 ,
} ,
} ;
static const struct regmap_range_cfg regmap_range_cfg1 [ ] = {
{
. range_min = 0x0000 ,
. range_max = 0x01ff ,
. selector_reg = 0x00 ,
. selector_mask = 0xff ,
. selector_shift = 0 ,
. window_start = 0x00 ,
. window_len = 0x100 ,
} ,
} ;
static const struct regmap_config regmap_config0 = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = 0x3fff ,
. ranges = regmap_range_cfg0 ,
. num_ranges = ARRAY_SIZE ( regmap_range_cfg0 ) ,
. cache_type = REGCACHE_NONE ,
} ;
static const struct regmap_config regmap_config1 = {
. reg_bits = 8 ,
. val_bits = 8 ,
. max_register = 0x01ff ,
. ranges = regmap_range_cfg1 ,
. num_ranges = ARRAY_SIZE ( regmap_range_cfg1 ) ,
. cache_type = REGCACHE_NONE ,
} ;
2011-11-24 18:59:53 +04:00
2016-08-10 02:49:09 +03:00
dev_dbg ( & client - > dev , " \n " ) ;
priv = kzalloc ( sizeof ( * priv ) , GFP_KERNEL ) ;
2012-07-20 04:10:36 +04:00
if ( ! priv ) {
ret = - ENOMEM ;
2016-08-10 02:49:09 +03:00
goto err ;
2012-07-20 04:10:36 +04:00
}
2011-04-07 23:27:43 +04:00
2016-08-10 02:49:09 +03:00
priv - > client [ 0 ] = client ;
2017-01-17 00:27:41 +03:00
priv - > fe . demodulator_priv = priv ;
2016-08-10 02:49:09 +03:00
priv - > i2c = client - > adapter ;
priv - > ts_mode = pdata - > ts_mode ;
priv - > ts_clk_inv = pdata - > ts_clk_inv ;
priv - > if_agc_polarity = pdata - > if_agc_polarity ;
priv - > spec_inv = pdata - > spec_inv ;
gpio_chip_base = * pdata - > gpio_chip_base ;
2016-08-13 19:19:05 +03:00
priv - > regmap [ 0 ] = regmap_init_i2c ( priv - > client [ 0 ] , & regmap_config0 ) ;
if ( IS_ERR ( priv - > regmap [ 0 ] ) ) {
ret = PTR_ERR ( priv - > regmap [ 0 ] ) ;
goto err_kfree ;
}
2016-08-10 02:49:09 +03:00
/* Check demod answers with correct chip id */
2016-08-13 19:19:05 +03:00
ret = regmap_read ( priv - > regmap [ 0 ] , 0x00fd , & utmp ) ;
2016-08-10 02:49:09 +03:00
if ( ret )
2016-08-13 19:19:05 +03:00
goto err_regmap_0_regmap_exit ;
2011-11-24 18:59:53 +04:00
2016-08-13 19:19:05 +03:00
dev_dbg ( & client - > dev , " chip_id=%02x \n " , utmp ) ;
2016-08-10 02:49:09 +03:00
2016-08-13 19:19:05 +03:00
if ( utmp ! = 0xe1 ) {
2016-08-10 02:49:09 +03:00
ret = - ENODEV ;
2016-08-13 19:19:05 +03:00
goto err_regmap_0_regmap_exit ;
2016-08-10 02:49:09 +03:00
}
/*
* Chip has two I2C addresses for different register banks . We register
* one dummy I2C client in in order to get own I2C client for each
* register bank .
*/
priv - > client [ 1 ] = i2c_new_dummy ( client - > adapter , client - > addr | ( 1 < < 1 ) ) ;
if ( ! priv - > client [ 1 ] ) {
ret = - ENODEV ;
dev_err ( & client - > dev , " I2C registration failed \n " ) ;
if ( ret )
2016-08-13 19:19:05 +03:00
goto err_regmap_0_regmap_exit ;
}
priv - > regmap [ 1 ] = regmap_init_i2c ( priv - > client [ 1 ] , & regmap_config1 ) ;
if ( IS_ERR ( priv - > regmap [ 1 ] ) ) {
ret = PTR_ERR ( priv - > regmap [ 1 ] ) ;
goto err_client_1_i2c_unregister_device ;
2016-08-10 02:49:09 +03:00
}
2011-11-24 18:59:53 +04:00
2012-07-20 04:10:36 +04:00
if ( gpio_chip_base ) {
2012-08-17 04:07:23 +04:00
# ifdef CONFIG_GPIOLIB
2016-08-10 02:49:09 +03:00
/* Add GPIOs */
2012-07-20 04:10:36 +04:00
priv - > gpio_chip . label = KBUILD_MODNAME ;
2016-08-10 04:00:37 +03:00
priv - > gpio_chip . parent = & client - > dev ;
2012-07-20 04:10:36 +04:00
priv - > gpio_chip . owner = THIS_MODULE ;
2016-08-10 02:49:09 +03:00
priv - > gpio_chip . direction_output = cxd2820r_gpio_direction_output ;
2012-07-20 04:10:36 +04:00
priv - > gpio_chip . set = cxd2820r_gpio_set ;
priv - > gpio_chip . get = cxd2820r_gpio_get ;
2016-08-10 02:49:09 +03:00
priv - > gpio_chip . base = - 1 ; /* Dynamic allocation */
2012-07-20 04:10:36 +04:00
priv - > gpio_chip . ngpio = GPIO_COUNT ;
priv - > gpio_chip . can_sleep = 1 ;
2015-12-09 16:46:55 +03:00
ret = gpiochip_add_data ( & priv - > gpio_chip , priv ) ;
2012-07-20 04:10:36 +04:00
if ( ret )
2016-08-13 19:19:05 +03:00
goto err_regmap_1_regmap_exit ;
2012-07-20 04:10:36 +04:00
2016-08-10 04:00:37 +03:00
dev_dbg ( & client - > dev , " gpio_chip.base=%d \n " ,
priv - > gpio_chip . base ) ;
2012-07-20 04:10:36 +04:00
* 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 )
2016-08-13 19:19:05 +03:00
goto err_regmap_1_regmap_exit ;
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
2016-08-10 02:49:09 +03:00
/* Create dvb frontend */
memcpy ( & priv - > fe . ops , & cxd2820r_ops , sizeof ( priv - > fe . ops ) ) ;
if ( ! pdata - > attach_in_use )
priv - > fe . ops . release = NULL ;
i2c_set_clientdata ( client , priv ) ;
/* Setup callbacks */
pdata - > get_dvb_frontend = cxd2820r_get_dvb_frontend ;
dev_info ( & client - > dev , " Sony CXD2820R successfully identified \n " ) ;
return 0 ;
2016-08-13 19:19:05 +03:00
err_regmap_1_regmap_exit :
regmap_exit ( priv - > regmap [ 1 ] ) ;
2016-08-10 02:49:09 +03:00
err_client_1_i2c_unregister_device :
i2c_unregister_device ( priv - > client [ 1 ] ) ;
2016-08-13 19:19:05 +03:00
err_regmap_0_regmap_exit :
regmap_exit ( priv - > regmap [ 0 ] ) ;
2016-08-10 02:49:09 +03:00
err_kfree :
2011-04-07 23:27:43 +04:00
kfree ( priv ) ;
2016-08-10 02:49:09 +03:00
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
return ret ;
2011-04-07 23:27:43 +04:00
}
2016-08-10 02:49:09 +03:00
static int cxd2820r_remove ( struct i2c_client * client )
{
struct cxd2820r_priv * priv = i2c_get_clientdata ( client ) ;
dev_dbg ( & client - > dev , " \n " ) ;
# ifdef CONFIG_GPIOLIB
if ( priv - > gpio_chip . label )
gpiochip_remove ( & priv - > gpio_chip ) ;
# endif
2016-08-13 19:19:05 +03:00
regmap_exit ( priv - > regmap [ 1 ] ) ;
2016-08-10 02:49:09 +03:00
i2c_unregister_device ( priv - > client [ 1 ] ) ;
2016-08-13 19:19:05 +03:00
regmap_exit ( priv - > regmap [ 0 ] ) ;
2016-08-10 02:49:09 +03:00
kfree ( priv ) ;
return 0 ;
}
static const struct i2c_device_id cxd2820r_id_table [ ] = {
{ " cxd2820r " , 0 } ,
{ }
} ;
MODULE_DEVICE_TABLE ( i2c , cxd2820r_id_table ) ;
static struct i2c_driver cxd2820r_driver = {
. driver = {
. name = " cxd2820r " ,
. suppress_bind_attrs = true ,
} ,
. probe = cxd2820r_probe ,
. remove = cxd2820r_remove ,
. id_table = cxd2820r_id_table ,
} ;
module_i2c_driver ( cxd2820r_driver ) ;
2011-04-07 23:27:43 +04:00
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
MODULE_DESCRIPTION ( " Sony CXD2820R demodulator driver " ) ;
MODULE_LICENSE ( " GPL " ) ;