2012-09-01 21:09:21 -03:00
/*
* Elonics E4000 silicon tuner driver
*
* Copyright ( C ) 2012 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 "e4000_priv.h"
2015-05-12 14:26:07 -03:00
static int e4000_init ( struct e4000_dev * dev )
2012-09-01 21:09:21 -03:00
{
2015-04-21 17:13:39 -03:00
struct i2c_client * client = dev - > client ;
2012-09-01 21:09:21 -03:00
int ret ;
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " \n " ) ;
2012-09-01 21:09:21 -03:00
/* reset */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x00 , 0x01 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* disable output clock */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x06 , 0x00 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x7a , 0x96 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* configure gains */
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x7e , " \x01 \xfe " , 2 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x82 , 0x00 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x24 , 0x05 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x87 , " \x20 \x01 " , 2 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x9f , " \x7f \x07 " , 2 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* DC offset control */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x2d , 0x1f ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2013-07-24 02:04:12 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x70 , " \x01 \x01 " , 2 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* gain control */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x1a , 0x17 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x1f , 0x1a ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
dev - > active = true ;
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2012-09-01 21:09:21 -03:00
return ret ;
}
2015-05-12 14:26:07 -03:00
static int e4000_sleep ( struct e4000_dev * dev )
2012-09-01 21:09:21 -03:00
{
2015-04-21 17:13:39 -03:00
struct i2c_client * client = dev - > client ;
2012-09-01 21:09:21 -03:00
int ret ;
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " \n " ) ;
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
dev - > active = false ;
2014-02-07 02:55:57 -03:00
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x00 , 0x00 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2012-09-01 21:09:21 -03:00
return ret ;
}
2015-05-12 14:26:07 -03:00
static int e4000_set_params ( struct e4000_dev * dev )
2012-09-01 21:09:21 -03:00
{
2015-04-21 17:13:39 -03:00
struct i2c_client * client = dev - > client ;
2015-04-21 21:18:45 -03:00
int ret , i ;
unsigned int div_n , k , k_cw , div_out ;
2014-01-27 03:13:19 -03:00
u64 f_vco ;
2013-07-24 02:04:12 -03:00
u8 buf [ 5 ] , i_data [ 4 ] , q_data [ 4 ] ;
2012-09-01 21:09:21 -03:00
2015-05-12 14:26:07 -03:00
if ( ! dev - > active ) {
dev_dbg ( & client - > dev , " tuner is sleeping \n " ) ;
return 0 ;
}
2012-09-01 21:09:21 -03:00
/* gain control manual */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x1a , 0x00 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 21:18:45 -03:00
/*
* Fractional - N synthesizer
*
* + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* v |
* Fref + - - - - + + - - - - - - - + + - - - - - - + + - - - +
* - - - - - - > | PD | - - > | VCO | - - - - - - > | / N . F | < - - | K |
* + - - - - + + - - - - - - - + + - - - - - - + + - - - +
* |
* |
* v
* + - - - - - - - + Fout
* | / Rout | - - - - - - >
* + - - - - - - - +
*/
2012-09-01 21:09:21 -03:00
for ( i = 0 ; i < ARRAY_SIZE ( e4000_pll_lut ) ; i + + ) {
2015-05-12 14:26:07 -03:00
if ( dev - > f_frequency < = e4000_pll_lut [ i ] . freq )
2012-09-01 21:09:21 -03:00
break ;
}
2013-12-29 19:47:35 -03:00
if ( i = = ARRAY_SIZE ( e4000_pll_lut ) ) {
ret = - EINVAL ;
2012-09-01 21:09:21 -03:00
goto err ;
2013-12-29 19:47:35 -03:00
}
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
# define F_REF dev->clk
2015-04-21 21:18:45 -03:00
div_out = e4000_pll_lut [ i ] . div_out ;
2015-05-12 14:26:07 -03:00
f_vco = ( u64 ) dev - > f_frequency * div_out ;
2015-04-21 21:18:45 -03:00
/* calculate PLL integer and fractional control word */
div_n = div_u64_rem ( f_vco , F_REF , & k ) ;
k_cw = div_u64 ( ( u64 ) k * 0x10000 , F_REF ) ;
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev ,
2015-05-12 14:26:07 -03:00
" frequency=%u bandwidth=%u f_vco=%llu F_REF=%u div_n=%u k=%u k_cw=%04x div_out=%u \n " ,
dev - > f_frequency , dev - > f_bandwidth , f_vco , F_REF , div_n , k ,
k_cw , div_out ) ;
2012-09-01 21:09:21 -03:00
2015-04-21 21:18:45 -03:00
buf [ 0 ] = div_n ;
buf [ 1 ] = ( k_cw > > 0 ) & 0xff ;
buf [ 2 ] = ( k_cw > > 8 ) & 0xff ;
buf [ 3 ] = 0x00 ;
buf [ 4 ] = e4000_pll_lut [ i ] . div_out_reg ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x09 , buf , 5 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* LNA filter (RF filter) */
for ( i = 0 ; i < ARRAY_SIZE ( e400_lna_filter_lut ) ; i + + ) {
2015-05-12 14:26:07 -03:00
if ( dev - > f_frequency < = e400_lna_filter_lut [ i ] . freq )
2012-09-01 21:09:21 -03:00
break ;
}
2013-12-29 19:47:35 -03:00
if ( i = = ARRAY_SIZE ( e400_lna_filter_lut ) ) {
ret = - EINVAL ;
2012-09-01 21:09:21 -03:00
goto err ;
2013-12-29 19:47:35 -03:00
}
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x10 , e400_lna_filter_lut [ i ] . val ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* IF filters */
for ( i = 0 ; i < ARRAY_SIZE ( e4000_if_filter_lut ) ; i + + ) {
2015-05-12 14:26:07 -03:00
if ( dev - > f_bandwidth < = e4000_if_filter_lut [ i ] . freq )
2012-09-01 21:09:21 -03:00
break ;
}
2013-12-29 19:47:35 -03:00
if ( i = = ARRAY_SIZE ( e4000_if_filter_lut ) ) {
ret = - EINVAL ;
2012-09-01 21:09:21 -03:00
goto err ;
2013-12-29 19:47:35 -03:00
}
2012-09-01 21:09:21 -03:00
buf [ 0 ] = e4000_if_filter_lut [ i ] . reg11_val ;
buf [ 1 ] = e4000_if_filter_lut [ i ] . reg12_val ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x11 , buf , 2 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
/* frequency band */
for ( i = 0 ; i < ARRAY_SIZE ( e4000_band_lut ) ; i + + ) {
2015-05-12 14:26:07 -03:00
if ( dev - > f_frequency < = e4000_band_lut [ i ] . freq )
2012-09-01 21:09:21 -03:00
break ;
}
2013-12-29 19:47:35 -03:00
if ( i = = ARRAY_SIZE ( e4000_band_lut ) ) {
ret = - EINVAL ;
2012-09-01 21:09:21 -03:00
goto err ;
2013-12-29 19:47:35 -03:00
}
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x07 , e4000_band_lut [ i ] . reg07_val ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x78 , e4000_band_lut [ i ] . reg78_val ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2013-07-24 02:04:12 -03:00
/* DC offset */
for ( i = 0 ; i < 4 ; i + + ) {
if ( i = = 0 )
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x15 , " \x00 \x7e \x24 " , 3 ) ;
2013-07-24 02:04:12 -03:00
else if ( i = = 1 )
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x15 , " \x00 \x7f " , 2 ) ;
2013-07-24 02:04:12 -03:00
else if ( i = = 2 )
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x15 , " \x01 " , 1 ) ;
2013-07-24 02:04:12 -03:00
else
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x16 , " \x7e " , 1 ) ;
2013-07-24 02:04:12 -03:00
2014-02-10 22:52:51 -03:00
if ( ret )
2013-07-24 02:04:12 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x29 , 0x01 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2013-07-24 02:04:12 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_read ( dev - > regmap , 0x2a , buf , 3 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2013-07-24 02:04:12 -03:00
goto err ;
i_data [ i ] = ( ( ( buf [ 2 ] > > 0 ) & 0x3 ) < < 6 ) | ( buf [ 0 ] & 0x3f ) ;
q_data [ i ] = ( ( ( buf [ 2 ] > > 4 ) & 0x3 ) < < 6 ) | ( buf [ 1 ] & 0x3f ) ;
}
2013-07-24 18:33:51 -03:00
swap ( q_data [ 2 ] , q_data [ 3 ] ) ;
swap ( i_data [ 2 ] , i_data [ 3 ] ) ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x50 , q_data , 4 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2013-07-24 02:04:12 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
ret = regmap_bulk_write ( dev - > regmap , 0x60 , i_data , 4 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2013-07-24 02:04:12 -03:00
goto err ;
2012-09-01 21:09:21 -03:00
/* gain control auto */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x1a , 0x17 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2012-09-01 21:09:21 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2012-09-01 21:09:21 -03:00
return ret ;
}
2015-05-12 14:26:07 -03:00
/*
* V4L2 API
*/
# if IS_ENABLED(CONFIG_VIDEO_V4L2)
static const struct v4l2_frequency_band bands [ ] = {
{
. type = V4L2_TUNER_RF ,
. index = 0 ,
. capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS ,
. rangelow = 59000000 ,
. rangehigh = 1105000000 ,
} ,
{
. type = V4L2_TUNER_RF ,
. index = 1 ,
. capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS ,
. rangelow = 1249000000 ,
2015-05-22 04:39:54 -03:00
. rangehigh = 2208000000UL ,
2015-05-12 14:26:07 -03:00
} ,
} ;
static inline struct e4000_dev * e4000_subdev_to_dev ( struct v4l2_subdev * sd )
2012-09-01 21:09:21 -03:00
{
2015-05-12 14:26:07 -03:00
return container_of ( sd , struct e4000_dev , sd ) ;
}
static int e4000_s_power ( struct v4l2_subdev * sd , int on )
{
struct e4000_dev * dev = e4000_subdev_to_dev ( sd ) ;
2015-04-21 17:13:39 -03:00
struct i2c_client * client = dev - > client ;
2015-05-12 14:26:07 -03:00
int ret ;
2012-09-01 21:09:21 -03:00
2015-05-12 14:26:07 -03:00
dev_dbg ( & client - > dev , " on=%d \n " , on ) ;
2012-09-01 21:09:21 -03:00
2015-05-12 14:26:07 -03:00
if ( on )
ret = e4000_init ( dev ) ;
else
ret = e4000_sleep ( dev ) ;
if ( ret )
return ret ;
return e4000_set_params ( dev ) ;
}
static const struct v4l2_subdev_core_ops e4000_subdev_core_ops = {
. s_power = e4000_s_power ,
} ;
2012-09-01 21:09:21 -03:00
2015-05-12 14:26:07 -03:00
static int e4000_g_tuner ( struct v4l2_subdev * sd , struct v4l2_tuner * v )
{
struct e4000_dev * dev = e4000_subdev_to_dev ( sd ) ;
struct i2c_client * client = dev - > client ;
dev_dbg ( & client - > dev , " index=%d \n " , v - > index ) ;
strlcpy ( v - > name , " Elonics E4000 " , sizeof ( v - > name ) ) ;
v - > type = V4L2_TUNER_RF ;
v - > capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS ;
v - > rangelow = bands [ 0 ] . rangelow ;
v - > rangehigh = bands [ 1 ] . rangehigh ;
2012-09-01 21:09:21 -03:00
return 0 ;
}
2015-05-12 14:26:07 -03:00
static int e4000_s_tuner ( struct v4l2_subdev * sd , const struct v4l2_tuner * v )
{
struct e4000_dev * dev = e4000_subdev_to_dev ( sd ) ;
struct i2c_client * client = dev - > client ;
dev_dbg ( & client - > dev , " index=%d \n " , v - > index ) ;
return 0 ;
}
static int e4000_g_frequency ( struct v4l2_subdev * sd , struct v4l2_frequency * f )
{
struct e4000_dev * dev = e4000_subdev_to_dev ( sd ) ;
struct i2c_client * client = dev - > client ;
dev_dbg ( & client - > dev , " tuner=%d \n " , f - > tuner ) ;
f - > frequency = dev - > f_frequency ;
return 0 ;
}
static int e4000_s_frequency ( struct v4l2_subdev * sd ,
const struct v4l2_frequency * f )
{
struct e4000_dev * dev = e4000_subdev_to_dev ( sd ) ;
struct i2c_client * client = dev - > client ;
dev_dbg ( & client - > dev , " tuner=%d type=%d frequency=%u \n " ,
f - > tuner , f - > type , f - > frequency ) ;
dev - > f_frequency = clamp_t ( unsigned int , f - > frequency ,
bands [ 0 ] . rangelow , bands [ 1 ] . rangehigh ) ;
return e4000_set_params ( dev ) ;
}
static int e4000_enum_freq_bands ( struct v4l2_subdev * sd ,
struct v4l2_frequency_band * band )
{
struct e4000_dev * dev = e4000_subdev_to_dev ( sd ) ;
struct i2c_client * client = dev - > client ;
dev_dbg ( & client - > dev , " tuner=%d type=%d index=%d \n " ,
band - > tuner , band - > type , band - > index ) ;
if ( band - > index > = ARRAY_SIZE ( bands ) )
return - EINVAL ;
band - > capability = bands [ band - > index ] . capability ;
band - > rangelow = bands [ band - > index ] . rangelow ;
band - > rangehigh = bands [ band - > index ] . rangehigh ;
return 0 ;
}
static const struct v4l2_subdev_tuner_ops e4000_subdev_tuner_ops = {
. g_tuner = e4000_g_tuner ,
. s_tuner = e4000_s_tuner ,
. g_frequency = e4000_g_frequency ,
. s_frequency = e4000_s_frequency ,
. enum_freq_bands = e4000_enum_freq_bands ,
} ;
static const struct v4l2_subdev_ops e4000_subdev_ops = {
. core = & e4000_subdev_core_ops ,
. tuner = & e4000_subdev_tuner_ops ,
} ;
2014-01-26 21:02:53 -03:00
static int e4000_set_lna_gain ( struct dvb_frontend * fe )
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = fe - > tuner_priv ;
struct i2c_client * client = dev - > client ;
2014-01-26 21:02:53 -03:00
int ret ;
u8 u8tmp ;
2014-02-08 04:21:10 -03:00
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " lna auto=%d->%d val=%d->%d \n " ,
dev - > lna_gain_auto - > cur . val , dev - > lna_gain_auto - > val ,
dev - > lna_gain - > cur . val , dev - > lna_gain - > val ) ;
2014-01-26 21:02:53 -03:00
2015-04-21 17:13:39 -03:00
if ( dev - > lna_gain_auto - > val & & dev - > if_gain_auto - > cur . val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x17 ;
2015-04-21 17:13:39 -03:00
else if ( dev - > lna_gain_auto - > val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x19 ;
2015-04-21 17:13:39 -03:00
else if ( dev - > if_gain_auto - > cur . val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x16 ;
else
u8tmp = 0x10 ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x1a , u8tmp ) ;
2014-01-26 21:02:53 -03:00
if ( ret )
goto err ;
2015-04-21 17:13:39 -03:00
if ( dev - > lna_gain_auto - > val = = false ) {
ret = regmap_write ( dev - > regmap , 0x14 , dev - > lna_gain - > val ) ;
2014-01-26 21:02:53 -03:00
if ( ret )
goto err ;
}
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2014-01-26 21:02:53 -03:00
return ret ;
}
static int e4000_set_mixer_gain ( struct dvb_frontend * fe )
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = fe - > tuner_priv ;
struct i2c_client * client = dev - > client ;
2014-01-26 21:02:53 -03:00
int ret ;
u8 u8tmp ;
2014-02-08 04:21:10 -03:00
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " mixer auto=%d->%d val=%d->%d \n " ,
dev - > mixer_gain_auto - > cur . val , dev - > mixer_gain_auto - > val ,
dev - > mixer_gain - > cur . val , dev - > mixer_gain - > val ) ;
2014-01-26 21:02:53 -03:00
2015-04-21 17:13:39 -03:00
if ( dev - > mixer_gain_auto - > val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x15 ;
else
u8tmp = 0x14 ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x20 , u8tmp ) ;
2014-01-26 21:02:53 -03:00
if ( ret )
goto err ;
2015-04-21 17:13:39 -03:00
if ( dev - > mixer_gain_auto - > val = = false ) {
ret = regmap_write ( dev - > regmap , 0x15 , dev - > mixer_gain - > val ) ;
2014-01-26 21:02:53 -03:00
if ( ret )
goto err ;
}
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2014-01-26 21:02:53 -03:00
return ret ;
}
static int e4000_set_if_gain ( struct dvb_frontend * fe )
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = fe - > tuner_priv ;
struct i2c_client * client = dev - > client ;
2014-01-26 21:02:53 -03:00
int ret ;
u8 buf [ 2 ] ;
u8 u8tmp ;
2014-02-08 04:21:10 -03:00
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " if auto=%d->%d val=%d->%d \n " ,
dev - > if_gain_auto - > cur . val , dev - > if_gain_auto - > val ,
dev - > if_gain - > cur . val , dev - > if_gain - > val ) ;
2014-01-26 21:02:53 -03:00
2015-04-21 17:13:39 -03:00
if ( dev - > if_gain_auto - > val & & dev - > lna_gain_auto - > cur . val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x17 ;
2015-04-21 17:13:39 -03:00
else if ( dev - > lna_gain_auto - > cur . val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x19 ;
2015-04-21 17:13:39 -03:00
else if ( dev - > if_gain_auto - > val )
2014-01-26 21:02:53 -03:00
u8tmp = 0x16 ;
else
u8tmp = 0x10 ;
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x1a , u8tmp ) ;
2014-01-26 21:02:53 -03:00
if ( ret )
goto err ;
2015-04-21 17:13:39 -03:00
if ( dev - > if_gain_auto - > val = = false ) {
buf [ 0 ] = e4000_if_gain_lut [ dev - > if_gain - > val ] . reg16_val ;
buf [ 1 ] = e4000_if_gain_lut [ dev - > if_gain - > val ] . reg17_val ;
ret = regmap_bulk_write ( dev - > regmap , 0x16 , buf , 2 ) ;
2014-01-26 21:02:53 -03:00
if ( ret )
goto err ;
}
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2014-01-26 21:02:53 -03:00
return ret ;
}
2014-02-07 02:55:57 -03:00
static int e4000_pll_lock ( struct dvb_frontend * fe )
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = fe - > tuner_priv ;
struct i2c_client * client = dev - > client ;
2014-02-07 02:55:57 -03:00
int ret ;
2015-04-21 17:13:39 -03:00
unsigned int uitmp ;
2014-02-07 02:55:57 -03:00
2015-04-21 17:13:39 -03:00
ret = regmap_read ( dev - > regmap , 0x07 , & uitmp ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2014-02-07 02:55:57 -03:00
goto err ;
2015-04-21 17:13:39 -03:00
dev - > pll_lock - > val = ( uitmp & 0x01 ) ;
2014-02-07 02:55:57 -03:00
2015-04-21 17:13:39 -03:00
return 0 ;
err :
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2014-02-07 02:55:57 -03:00
return ret ;
}
static int e4000_g_volatile_ctrl ( struct v4l2_ctrl * ctrl )
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = container_of ( ctrl - > handler , struct e4000_dev , hdl ) ;
struct i2c_client * client = dev - > client ;
2014-02-07 02:55:57 -03:00
int ret ;
2015-04-21 17:13:39 -03:00
if ( ! dev - > active )
2014-02-08 06:20:35 -03:00
return 0 ;
2014-02-07 02:55:57 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_RF_TUNER_PLL_LOCK :
2015-04-21 17:13:39 -03:00
ret = e4000_pll_lock ( dev - > fe ) ;
2014-02-07 02:55:57 -03:00
break ;
default :
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " unknown ctrl: id=%d name=%s \n " ,
ctrl - > id , ctrl - > name ) ;
2014-02-07 02:55:57 -03:00
ret = - EINVAL ;
}
return ret ;
}
2014-01-26 21:02:53 -03:00
static int e4000_s_ctrl ( struct v4l2_ctrl * ctrl )
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = container_of ( ctrl - > handler , struct e4000_dev , hdl ) ;
struct i2c_client * client = dev - > client ;
2014-01-26 21:02:53 -03:00
int ret ;
2014-02-08 04:21:10 -03:00
2015-04-21 17:13:39 -03:00
if ( ! dev - > active )
2014-02-08 06:20:35 -03:00
return 0 ;
2014-01-26 21:02:53 -03:00
switch ( ctrl - > id ) {
case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO :
case V4L2_CID_RF_TUNER_BANDWIDTH :
2015-05-12 14:26:07 -03:00
/*
* TODO : Auto logic does not work 100 % correctly as tuner driver
* do not have information to calculate maximum suitable
* bandwidth . Calculating it is responsible of master driver .
*/
dev - > f_bandwidth = dev - > bandwidth - > val ;
ret = e4000_set_params ( dev ) ;
2014-01-26 21:02:53 -03:00
break ;
case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO :
case V4L2_CID_RF_TUNER_LNA_GAIN :
2015-04-21 17:13:39 -03:00
ret = e4000_set_lna_gain ( dev - > fe ) ;
2014-01-26 21:02:53 -03:00
break ;
case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO :
case V4L2_CID_RF_TUNER_MIXER_GAIN :
2015-04-21 17:13:39 -03:00
ret = e4000_set_mixer_gain ( dev - > fe ) ;
2014-01-26 21:02:53 -03:00
break ;
case V4L2_CID_RF_TUNER_IF_GAIN_AUTO :
case V4L2_CID_RF_TUNER_IF_GAIN :
2015-04-21 17:13:39 -03:00
ret = e4000_set_if_gain ( dev - > fe ) ;
2014-01-26 21:02:53 -03:00
break ;
default :
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " unknown ctrl: id=%d name=%s \n " ,
ctrl - > id , ctrl - > name ) ;
2014-01-26 21:02:53 -03:00
ret = - EINVAL ;
}
return ret ;
}
static const struct v4l2_ctrl_ops e4000_ctrl_ops = {
2014-02-07 02:55:57 -03:00
. g_volatile_ctrl = e4000_g_volatile_ctrl ,
2014-01-26 21:02:53 -03:00
. s_ctrl = e4000_s_ctrl ,
} ;
2014-03-16 18:13:05 -03:00
# endif
2014-01-26 21:02:53 -03:00
2015-05-12 14:26:07 -03:00
/*
* DVB API
*/
static int e4000_dvb_set_params ( struct dvb_frontend * fe )
{
struct e4000_dev * dev = fe - > tuner_priv ;
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
dev - > f_frequency = c - > frequency ;
dev - > f_bandwidth = c - > bandwidth_hz ;
return e4000_set_params ( dev ) ;
}
static int e4000_dvb_init ( struct dvb_frontend * fe )
{
return e4000_init ( fe - > tuner_priv ) ;
}
static int e4000_dvb_sleep ( struct dvb_frontend * fe )
{
return e4000_sleep ( fe - > tuner_priv ) ;
}
static int e4000_dvb_get_if_frequency ( struct dvb_frontend * fe , u32 * frequency )
{
* frequency = 0 ; /* Zero-IF */
return 0 ;
}
static const struct dvb_tuner_ops e4000_dvb_tuner_ops = {
2012-09-01 21:09:21 -03:00
. info = {
. name = " Elonics E4000 " ,
. frequency_min = 174000000 ,
. frequency_max = 862000000 ,
} ,
2015-05-12 14:26:07 -03:00
. init = e4000_dvb_init ,
. sleep = e4000_dvb_sleep ,
. set_params = e4000_dvb_set_params ,
2012-09-01 21:09:21 -03:00
2015-05-12 14:26:07 -03:00
. get_if_frequency = e4000_dvb_get_if_frequency ,
2012-09-01 21:09:21 -03:00
} ;
2013-10-15 19:22:45 -03:00
static int e4000_probe ( struct i2c_client * client ,
2015-04-21 17:13:39 -03:00
const struct i2c_device_id * id )
2012-09-01 21:09:21 -03:00
{
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev ;
2013-10-15 19:22:45 -03:00
struct e4000_config * cfg = client - > dev . platform_data ;
struct dvb_frontend * fe = cfg - > fe ;
2012-09-01 21:09:21 -03:00
int ret ;
2015-04-21 17:13:39 -03:00
unsigned int uitmp ;
2014-02-08 06:20:35 -03:00
static const struct regmap_config regmap_config = {
. reg_bits = 8 ,
. val_bits = 8 ,
} ;
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
dev = kzalloc ( sizeof ( * dev ) , GFP_KERNEL ) ;
if ( ! dev ) {
2012-09-01 21:09:21 -03:00
ret = - ENOMEM ;
goto err ;
}
2015-04-21 17:13:39 -03:00
dev - > clk = cfg - > clock ;
dev - > client = client ;
dev - > fe = cfg - > fe ;
dev - > regmap = devm_regmap_init_i2c ( client , & regmap_config ) ;
if ( IS_ERR ( dev - > regmap ) ) {
ret = PTR_ERR ( dev - > regmap ) ;
goto err_kfree ;
2014-02-08 06:20:35 -03:00
}
2012-09-01 21:09:21 -03:00
/* check if the tuner is there */
2015-04-21 17:13:39 -03:00
ret = regmap_read ( dev - > regmap , 0x02 , & uitmp ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2015-04-21 17:13:39 -03:00
goto err_kfree ;
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " chip id=%02x \n " , uitmp ) ;
2012-09-01 21:09:21 -03:00
2015-04-21 17:13:39 -03:00
if ( uitmp ! = 0x40 ) {
2013-10-15 19:22:45 -03:00
ret = - ENODEV ;
2015-04-21 17:13:39 -03:00
goto err_kfree ;
2013-10-15 19:22:45 -03:00
}
2012-09-01 21:09:21 -03:00
/* put sleep as chip seems to be in normal mode by default */
2015-04-21 17:13:39 -03:00
ret = regmap_write ( dev - > regmap , 0x00 , 0x00 ) ;
2014-02-10 22:52:51 -03:00
if ( ret )
2015-04-21 17:13:39 -03:00
goto err_kfree ;
2012-09-01 21:09:21 -03:00
2014-03-16 18:13:05 -03:00
# if IS_ENABLED(CONFIG_VIDEO_V4L2)
2014-01-26 21:02:53 -03:00
/* Register controls */
2015-04-21 17:13:39 -03:00
v4l2_ctrl_handler_init ( & dev - > hdl , 9 ) ;
dev - > bandwidth_auto = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_BANDWIDTH_AUTO , 0 , 1 , 1 , 1 ) ;
2015-04-21 17:13:39 -03:00
dev - > bandwidth = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_BANDWIDTH , 4300000 , 11000000 , 100000 , 4300000 ) ;
2015-04-21 17:13:39 -03:00
v4l2_ctrl_auto_cluster ( 2 , & dev - > bandwidth_auto , 0 , false ) ;
dev - > lna_gain_auto = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_LNA_GAIN_AUTO , 0 , 1 , 1 , 1 ) ;
2015-04-21 17:13:39 -03:00
dev - > lna_gain = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_LNA_GAIN , 0 , 15 , 1 , 10 ) ;
2015-04-21 17:13:39 -03:00
v4l2_ctrl_auto_cluster ( 2 , & dev - > lna_gain_auto , 0 , false ) ;
dev - > mixer_gain_auto = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO , 0 , 1 , 1 , 1 ) ;
2015-04-21 17:13:39 -03:00
dev - > mixer_gain = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_MIXER_GAIN , 0 , 1 , 1 , 1 ) ;
2015-04-21 17:13:39 -03:00
v4l2_ctrl_auto_cluster ( 2 , & dev - > mixer_gain_auto , 0 , false ) ;
dev - > if_gain_auto = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_IF_GAIN_AUTO , 0 , 1 , 1 , 1 ) ;
2015-04-21 17:13:39 -03:00
dev - > if_gain = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-01-26 21:02:53 -03:00
V4L2_CID_RF_TUNER_IF_GAIN , 0 , 54 , 1 , 0 ) ;
2015-04-21 17:13:39 -03:00
v4l2_ctrl_auto_cluster ( 2 , & dev - > if_gain_auto , 0 , false ) ;
dev - > pll_lock = v4l2_ctrl_new_std ( & dev - > hdl , & e4000_ctrl_ops ,
2014-02-07 02:55:57 -03:00
V4L2_CID_RF_TUNER_PLL_LOCK , 0 , 1 , 1 , 0 ) ;
2015-04-21 17:13:39 -03:00
if ( dev - > hdl . error ) {
ret = dev - > hdl . error ;
dev_err ( & client - > dev , " Could not initialize controls \n " ) ;
v4l2_ctrl_handler_free ( & dev - > hdl ) ;
goto err_kfree ;
2014-01-26 21:02:53 -03:00
}
2015-04-21 17:13:39 -03:00
dev - > sd . ctrl_handler = & dev - > hdl ;
2015-05-12 14:26:07 -03:00
dev - > f_frequency = bands [ 0 ] . rangelow ;
dev - > f_bandwidth = dev - > bandwidth - > val ;
v4l2_i2c_subdev_init ( & dev - > sd , client , & e4000_subdev_ops ) ;
2014-03-16 18:13:05 -03:00
# endif
2015-04-21 17:13:39 -03:00
fe - > tuner_priv = dev ;
2015-05-12 14:26:07 -03:00
memcpy ( & fe - > ops . tuner_ops , & e4000_dvb_tuner_ops ,
sizeof ( fe - > ops . tuner_ops ) ) ;
2015-04-21 17:13:39 -03:00
v4l2_set_subdevdata ( & dev - > sd , client ) ;
i2c_set_clientdata ( client , & dev - > sd ) ;
2012-09-22 12:32:27 -03:00
2015-04-21 17:13:39 -03:00
dev_info ( & client - > dev , " Elonics E4000 successfully identified \n " ) ;
2013-10-15 19:22:45 -03:00
return 0 ;
2015-04-21 17:13:39 -03:00
err_kfree :
kfree ( dev ) ;
2012-09-01 21:09:21 -03:00
err :
2015-04-21 17:13:39 -03:00
dev_dbg ( & client - > dev , " failed=%d \n " , ret ) ;
2013-10-15 19:22:45 -03:00
return ret ;
2012-09-01 21:09:21 -03:00
}
2013-10-15 19:22:45 -03:00
static int e4000_remove ( struct i2c_client * client )
{
2014-01-26 21:02:53 -03:00
struct v4l2_subdev * sd = i2c_get_clientdata ( client ) ;
2015-04-21 17:13:39 -03:00
struct e4000_dev * dev = container_of ( sd , struct e4000_dev , sd ) ;
2013-10-15 19:22:45 -03:00
2014-08-24 23:35:48 -03:00
dev_dbg ( & client - > dev , " \n " ) ;
2014-02-08 04:21:10 -03:00
2014-03-16 18:13:05 -03:00
# if IS_ENABLED(CONFIG_VIDEO_V4L2)
2015-04-21 17:13:39 -03:00
v4l2_ctrl_handler_free ( & dev - > hdl ) ;
2014-03-16 18:13:05 -03:00
# endif
2015-04-21 17:13:39 -03:00
kfree ( dev ) ;
2013-10-15 19:22:45 -03:00
return 0 ;
}
2015-04-21 17:13:39 -03:00
static const struct i2c_device_id e4000_id_table [ ] = {
2013-10-15 19:22:45 -03:00
{ " e4000 " , 0 } ,
{ }
} ;
2015-04-21 17:13:39 -03:00
MODULE_DEVICE_TABLE ( i2c , e4000_id_table ) ;
2013-10-15 19:22:45 -03:00
static struct i2c_driver e4000_driver = {
. driver = {
. name = " e4000 " ,
2015-04-21 17:13:39 -03:00
. suppress_bind_attrs = true ,
2013-10-15 19:22:45 -03:00
} ,
. probe = e4000_probe ,
. remove = e4000_remove ,
2015-04-21 17:13:39 -03:00
. id_table = e4000_id_table ,
2013-10-15 19:22:45 -03:00
} ;
module_i2c_driver ( e4000_driver ) ;
2012-09-01 21:09:21 -03:00
MODULE_DESCRIPTION ( " Elonics E4000 silicon tuner driver " ) ;
MODULE_AUTHOR ( " Antti Palosaari <crope@iki.fi> " ) ;
MODULE_LICENSE ( " GPL " ) ;