2019-05-27 09:55:21 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2017-11-29 16:19:13 +03:00
/*
2010-08-29 01:07:37 +04:00
* Driver for Sharp IX2505V ( marked B0017 ) DVB - S silicon tuner
*
* Copyright ( C ) 2010 Malcolm Priestley
*/
# include <linux/module.h>
# include <linux/dvb/frontend.h>
# include <linux/slab.h>
# include <linux/types.h>
# include "ix2505v.h"
static int ix2505v_debug ;
V4L/DVB: ix2505v: make scripts/checkpatch.pl happy
WARNING: please, no space before tabs
+ * ^IPOR = Power on Reset (VCC H=<2.2v L=>2.2v)$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Frq=%d x=%d N=%d A=%d \n", frequency, x, N, A);
WARNING: please, no space before tabs
+^Ielse ^I^I/*frequency up to 2150000*/$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 0=[%x%x%x%x] \n", data[0], data[1], data[2], data[3]);
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 2=[%x%x] \n", data[2], data[3]);
Cc: Malcolm Priestley <tvboxspy@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2010-09-08 19:51:56 +04:00
# define dprintk(level, args...) do { \
if ( ix2505v_debug & level ) \
printk ( KERN_DEBUG " ix2505v: " args ) ; \
} while ( 0 )
2010-08-29 01:07:37 +04:00
# define deb_info(args...) dprintk(0x01, args)
# define deb_i2c(args...) dprintk(0x02, args)
struct ix2505v_state {
struct i2c_adapter * i2c ;
const struct ix2505v_config * config ;
u32 frequency ;
} ;
2017-11-29 16:19:13 +03:00
/*
2010-08-29 01:07:37 +04:00
* Data read format of the Sharp IX2505V B0017
*
* byte1 : 1 | 1 | 0 | 0 | 0 | MA1 | MA0 | 1
* byte2 : POR | FL | RD2 | RD1 | RD0 | X | X | X
*
* byte1 = address
* byte2 ;
V4L/DVB: ix2505v: make scripts/checkpatch.pl happy
WARNING: please, no space before tabs
+ * ^IPOR = Power on Reset (VCC H=<2.2v L=>2.2v)$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Frq=%d x=%d N=%d A=%d \n", frequency, x, N, A);
WARNING: please, no space before tabs
+^Ielse ^I^I/*frequency up to 2150000*/$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 0=[%x%x%x%x] \n", data[0], data[1], data[2], data[3]);
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 2=[%x%x] \n", data[2], data[3]);
Cc: Malcolm Priestley <tvboxspy@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2010-09-08 19:51:56 +04:00
* POR = Power on Reset ( VCC H = < 2.2 v L = > 2.2 v )
2010-08-29 01:07:37 +04:00
* FL = Phase Lock ( H = lock L = unlock )
* RD0 - 2 = Reserved internal operations
*
* Only POR can be used to check the tuner is present
*
* Caution : after byte2 the I2C reverts to write mode continuing to read
* may corrupt tuning data .
*
*/
static int ix2505v_read_status_reg ( struct ix2505v_state * state )
{
u8 addr = state - > config - > tuner_address ;
u8 b2 [ ] = { 0 } ;
int ret ;
struct i2c_msg msg [ 1 ] = {
{ . addr = addr , . flags = I2C_M_RD , . buf = b2 , . len = 1 }
} ;
ret = i2c_transfer ( state - > i2c , msg , 1 ) ;
deb_i2c ( " Read %s " , __func__ ) ;
2010-11-07 16:57:13 +03:00
return ( ret = = 1 ) ? ( int ) b2 [ 0 ] : - 1 ;
2010-08-29 01:07:37 +04:00
}
static int ix2505v_write ( struct ix2505v_state * state , u8 buf [ ] , u8 count )
{
struct i2c_msg msg [ 1 ] = {
{ . addr = state - > config - > tuner_address , . flags = 0 ,
. buf = buf , . len = count } ,
} ;
int ret ;
ret = i2c_transfer ( state - > i2c , msg , 1 ) ;
if ( ret ! = 1 ) {
deb_i2c ( " %s: i2c error, ret=%d \n " , __func__ , ret ) ;
return - EIO ;
}
return 0 ;
}
2016-11-19 01:30:51 +03:00
static void ix2505v_release ( struct dvb_frontend * fe )
{
struct ix2505v_state * state = fe - > tuner_priv ;
fe - > tuner_priv = NULL ;
kfree ( state ) ;
}
2017-11-29 16:19:13 +03:00
/*
2010-08-29 01:07:37 +04:00
* Data write format of the Sharp IX2505V B0017
*
* byte1 : 1 | 1 | 0 | 0 | 0 | 0 ( MA1 ) | 0 ( MA0 ) | 0
* byte2 : 0 | BG1 | BG2 | N8 | N7 | N6 | N5 | N4
* byte3 : N3 | N2 | N1 | A5 | A4 | A3 | A2 | A1
* byte4 : 1 | 1 ( C1 ) | 1 ( C0 ) | PD5 | PD4 | TM | 0 ( RTS ) | 1 ( REF )
* byte5 : BA2 | BA1 | BA0 | PSC | PD3 | PD2 / TS2 | DIV / TS1 | PD0 / TS0
*
* byte1 = address
*
* Write order
* 1 ) byte1 - > byte2 - > byte3 - > byte4 - > byte5
* 2 ) byte1 - > byte4 - > byte5 - > byte2 - > byte3
* 3 ) byte1 - > byte2 - > byte3 - > byte4
* 4 ) byte1 - > byte4 - > byte5 - > byte2
* 5 ) byte1 - > byte2 - > byte3
* 6 ) byte1 - > byte4 - > byte5
* 7 ) byte1 - > byte2
* 8 ) byte1 - > byte4
*
* Recommended Setup
* 1 - > 8 - > 6
*/
2011-12-24 19:24:33 +04:00
static int ix2505v_set_params ( struct dvb_frontend * fe )
2010-08-29 01:07:37 +04:00
{
2011-12-24 01:33:18 +04:00
struct dtv_frontend_properties * c = & fe - > dtv_property_cache ;
2010-08-29 01:07:37 +04:00
struct ix2505v_state * state = fe - > tuner_priv ;
2011-12-24 01:33:18 +04:00
u32 frequency = c - > frequency ;
u32 b_w = ( c - > symbol_rate * 27 ) / 32000 ;
2010-08-29 01:07:37 +04:00
u32 div_factor , N , A , x ;
int ret = 0 , len ;
u8 gain , cc , ref , psc , local_osc , lpf ;
u8 data [ 4 ] = { 0 } ;
2018-07-06 01:59:36 +03:00
if ( ( frequency < fe - > ops . info . frequency_min_hz / kHz )
| | ( frequency > fe - > ops . info . frequency_max_hz / kHz ) )
2010-08-29 01:07:37 +04:00
return - EINVAL ;
if ( state - > config - > tuner_gain )
gain = ( state - > config - > tuner_gain < 4 )
? state - > config - > tuner_gain : 0 ;
else
gain = 0x0 ;
if ( state - > config - > tuner_chargepump )
cc = state - > config - > tuner_chargepump ;
else
cc = 0x3 ;
ref = 8 ; /* REF =1 */
psc = 32 ; /* PSC = 0 */
div_factor = ( frequency * ref ) / 40 ; /* local osc = 4Mhz */
x = div_factor / psc ;
N = x / 100 ;
A = ( ( x - ( N * 100 ) ) * psc ) / 100 ;
data [ 0 ] = ( ( gain & 0x3 ) < < 5 ) | ( N > > 3 ) ;
data [ 1 ] = ( N < < 5 ) | ( A & 0x1f ) ;
data [ 2 ] = 0x81 | ( ( cc & 0x3 ) < < 5 ) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
V4L/DVB: ix2505v: make scripts/checkpatch.pl happy
WARNING: please, no space before tabs
+ * ^IPOR = Power on Reset (VCC H=<2.2v L=>2.2v)$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Frq=%d x=%d N=%d A=%d \n", frequency, x, N, A);
WARNING: please, no space before tabs
+^Ielse ^I^I/*frequency up to 2150000*/$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 0=[%x%x%x%x] \n", data[0], data[1], data[2], data[3]);
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 2=[%x%x] \n", data[2], data[3]);
Cc: Malcolm Priestley <tvboxspy@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2010-09-08 19:51:56 +04:00
deb_info ( " Frq=%d x=%d N=%d A=%d \n " , frequency , x , N , A ) ;
2010-08-29 01:07:37 +04:00
if ( frequency < = 1065000 )
local_osc = ( 6 < < 5 ) | 2 ;
else if ( frequency < = 1170000 )
local_osc = ( 7 < < 5 ) | 2 ;
else if ( frequency < = 1300000 )
local_osc = ( 1 < < 5 ) ;
else if ( frequency < = 1445000 )
local_osc = ( 2 < < 5 ) ;
else if ( frequency < = 1607000 )
local_osc = ( 3 < < 5 ) ;
else if ( frequency < = 1778000 )
local_osc = ( 4 < < 5 ) ;
else if ( frequency < = 1942000 )
local_osc = ( 5 < < 5 ) ;
V4L/DVB: ix2505v: make scripts/checkpatch.pl happy
WARNING: please, no space before tabs
+ * ^IPOR = Power on Reset (VCC H=<2.2v L=>2.2v)$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Frq=%d x=%d N=%d A=%d \n", frequency, x, N, A);
WARNING: please, no space before tabs
+^Ielse ^I^I/*frequency up to 2150000*/$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 0=[%x%x%x%x] \n", data[0], data[1], data[2], data[3]);
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 2=[%x%x] \n", data[2], data[3]);
Cc: Malcolm Priestley <tvboxspy@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2010-09-08 19:51:56 +04:00
else /*frequency up to 2150000*/
2010-08-29 01:07:37 +04:00
local_osc = ( 6 < < 5 ) ;
data [ 3 ] = local_osc ; /* all other bits set 0 */
if ( b_w < = 10000 )
lpf = 0xc ;
else if ( b_w < = 12000 )
lpf = 0x2 ;
else if ( b_w < = 14000 )
lpf = 0xa ;
else if ( b_w < = 16000 )
lpf = 0x6 ;
else if ( b_w < = 18000 )
lpf = 0xe ;
else if ( b_w < = 20000 )
lpf = 0x1 ;
else if ( b_w < = 22000 )
lpf = 0x9 ;
else if ( b_w < = 24000 )
lpf = 0x5 ;
else if ( b_w < = 26000 )
lpf = 0xd ;
else if ( b_w < = 28000 )
lpf = 0x3 ;
else
lpf = 0xb ;
deb_info ( " Osc=%x b_w=%x lpf=%x \n " , local_osc , b_w , lpf ) ;
2012-12-18 05:10:48 +04:00
deb_info ( " Data 0=[%4phN] \n " , data ) ;
2010-08-29 01:07:37 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
len = sizeof ( data ) ;
ret | = ix2505v_write ( state , data , len ) ;
data [ 2 ] | = 0x4 ; /* set TM = 1 other bits same */
2011-04-22 13:00:22 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2010-08-29 01:07:37 +04:00
len = 1 ;
ret | = ix2505v_write ( state , & data [ 2 ] , len ) ; /* write byte 4 only */
msleep ( 10 ) ;
data [ 2 ] | = ( ( lpf > > 2 ) & 0x3 ) < < 3 ; /* lpf */
data [ 3 ] | = ( lpf & 0x3 ) < < 2 ;
V4L/DVB: ix2505v: make scripts/checkpatch.pl happy
WARNING: please, no space before tabs
+ * ^IPOR = Power on Reset (VCC H=<2.2v L=>2.2v)$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Frq=%d x=%d N=%d A=%d \n", frequency, x, N, A);
WARNING: please, no space before tabs
+^Ielse ^I^I/*frequency up to 2150000*/$
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 0=[%x%x%x%x] \n", data[0], data[1], data[2], data[3]);
WARNING: unnecessary whitespace before a quoted newline
+ deb_info("Data 2=[%x%x] \n", data[2], data[3]);
Cc: Malcolm Priestley <tvboxspy@gmail.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
2010-09-08 19:51:56 +04:00
deb_info ( " Data 2=[%x%x] \n " , data [ 2 ] , data [ 3 ] ) ;
2010-08-29 01:07:37 +04:00
2011-04-22 13:00:22 +04:00
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
2010-08-29 01:07:37 +04:00
len = 2 ;
ret | = ix2505v_write ( state , & data [ 2 ] , len ) ; /* write byte 4 & 5 */
if ( state - > config - > min_delay_ms )
msleep ( state - > config - > min_delay_ms ) ;
state - > frequency = frequency ;
return ret ;
}
static int ix2505v_get_frequency ( struct dvb_frontend * fe , u32 * frequency )
{
struct ix2505v_state * state = fe - > tuner_priv ;
* frequency = state - > frequency ;
return 0 ;
}
2016-09-11 17:44:12 +03:00
static const struct dvb_tuner_ops ix2505v_tuner_ops = {
2010-08-29 01:07:37 +04:00
. info = {
. name = " Sharp IX2505V (B0017) " ,
2018-07-06 01:59:35 +03:00
. frequency_min_hz = 950 * MHz ,
. frequency_max_hz = 2175 * MHz
2010-08-29 01:07:37 +04:00
} ,
2016-11-19 01:30:51 +03:00
. release = ix2505v_release ,
2010-08-29 01:07:37 +04:00
. set_params = ix2505v_set_params ,
. get_frequency = ix2505v_get_frequency ,
} ;
struct dvb_frontend * ix2505v_attach ( struct dvb_frontend * fe ,
const struct ix2505v_config * config ,
struct i2c_adapter * i2c )
{
struct ix2505v_state * state = NULL ;
int ret ;
if ( NULL = = config ) {
deb_i2c ( " %s: no config " , __func__ ) ;
goto error ;
}
state = kzalloc ( sizeof ( struct ix2505v_state ) , GFP_KERNEL ) ;
if ( NULL = = state )
return NULL ;
state - > config = config ;
state - > i2c = i2c ;
if ( state - > config - > tuner_write_only ) {
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 1 ) ;
ret = ix2505v_read_status_reg ( state ) ;
if ( ret & 0x80 ) {
deb_i2c ( " %s: No IX2505V found \n " , __func__ ) ;
goto error ;
}
if ( fe - > ops . i2c_gate_ctrl )
fe - > ops . i2c_gate_ctrl ( fe , 0 ) ;
}
fe - > tuner_priv = state ;
memcpy ( & fe - > ops . tuner_ops , & ix2505v_tuner_ops ,
sizeof ( struct dvb_tuner_ops ) ) ;
deb_i2c ( " %s: initialization (%s addr=0x%02x) ok \n " ,
__func__ , fe - > ops . tuner_ops . info . name , config - > tuner_address ) ;
return fe ;
error :
2011-01-02 22:14:03 +03:00
kfree ( state ) ;
2010-08-29 01:07:37 +04:00
return NULL ;
}
EXPORT_SYMBOL ( ix2505v_attach ) ;
module_param_named ( debug , ix2505v_debug , int , 0644 ) ;
MODULE_PARM_DESC ( debug , " Turn on/off frontend debugging (default:off). " ) ;
MODULE_DESCRIPTION ( " DVB IX2505V tuner driver " ) ;
MODULE_AUTHOR ( " Malcolm Priestley " ) ;
MODULE_LICENSE ( " GPL " ) ;