2019-05-31 01:09:32 -07:00
// SPDX-License-Identifier: GPL-2.0-only
2005-09-09 13:02:41 -07:00
/* DVB frontend part of the Linux driver for the TwinhanDTV StarBox USB2.0
* DVB - S receiver .
*
* Copyright ( C ) 2005 Ralph Metzler < rjkm @ metzlerbros . de >
* Metzler Brothers Systementwicklung GbR
*
2016-01-24 12:56:58 -02:00
* Copyright ( C ) 2005 Patrick Boettcher < patrick . boettcher @ posteo . de >
2005-09-09 13:02:41 -07:00
*
* Thanks to Twinhan who kindly provided hardware and information .
*
* This file can be removed soon , after the DST - driver is rewritten to provice
* the frontend - controlling separately .
*
2020-03-04 15:54:10 +01:00
* see Documentation / driver - api / media / drivers / dvb - usb . rst for more information
2005-09-09 13:02:41 -07:00
*/
# include "vp702x.h"
struct vp702x_fe_state {
struct dvb_frontend fe ;
struct dvb_usb_device * d ;
2006-09-19 12:51:43 -03:00
struct dvb_frontend_ops ops ;
2015-06-07 14:53:52 -03:00
enum fe_sec_voltage voltage ;
enum fe_sec_tone_mode tone_mode ;
2005-09-09 13:02:41 -07:00
u8 lnb_buf [ 8 ] ;
u8 lock ;
u8 sig ;
u8 snr ;
unsigned long next_status_check ;
unsigned long status_check_interval ;
} ;
static int vp702x_fe_refresh_state ( struct vp702x_fe_state * st )
{
2011-03-21 07:19:14 -03:00
struct vp702x_device_state * dst = st - > d - > priv ;
2011-03-21 07:19:10 -03:00
u8 * buf ;
if ( time_after ( jiffies , st - > next_status_check ) ) {
2011-03-21 07:19:14 -03:00
mutex_lock ( & dst - > buf_mutex ) ;
buf = dst - > buf ;
2011-03-21 07:19:10 -03:00
vp702x_usb_in_op ( st - > d , READ_STATUS , 0 , 0 , buf , 10 ) ;
2005-09-09 13:02:41 -07:00
st - > lock = buf [ 4 ] ;
2011-03-21 07:19:10 -03:00
vp702x_usb_in_op ( st - > d , READ_TUNER_REG_REQ , 0x11 , 0 , buf , 1 ) ;
st - > snr = buf [ 0 ] ;
vp702x_usb_in_op ( st - > d , READ_TUNER_REG_REQ , 0x15 , 0 , buf , 1 ) ;
st - > sig = buf [ 0 ] ;
2011-03-21 07:19:14 -03:00
mutex_unlock ( & dst - > buf_mutex ) ;
2005-09-09 13:02:41 -07:00
st - > next_status_check = jiffies + ( st - > status_check_interval * HZ ) / 1000 ;
}
return 0 ;
}
static u8 vp702x_chksum ( u8 * buf , int f , int count )
{
u8 s = 0 ;
int i ;
for ( i = f ; i < f + count ; i + + )
s + = buf [ i ] ;
return ~ s + 1 ;
}
2015-06-07 14:53:52 -03:00
static int vp702x_fe_read_status ( struct dvb_frontend * fe ,
enum fe_status * status )
2005-09-09 13:02:41 -07:00
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
vp702x_fe_refresh_state ( st ) ;
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2005-09-09 13:02:41 -07:00
if ( st - > lock = = 0 )
* status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER ;
else
* status = 0 ;
if ( * status & FE_HAS_LOCK )
st - > status_check_interval = 1000 ;
else
st - > status_check_interval = 250 ;
return 0 ;
}
/* not supported by this Frontend */
static int vp702x_fe_read_ber ( struct dvb_frontend * fe , u32 * ber )
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
vp702x_fe_refresh_state ( st ) ;
* ber = 0 ;
return 0 ;
}
/* not supported by this Frontend */
static int vp702x_fe_read_unc_blocks ( struct dvb_frontend * fe , u32 * unc )
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
vp702x_fe_refresh_state ( st ) ;
* unc = 0 ;
return 0 ;
}
static int vp702x_fe_read_signal_strength ( struct dvb_frontend * fe , u16 * strength )
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
vp702x_fe_refresh_state ( st ) ;
* strength = ( st - > sig < < 8 ) | st - > sig ;
return 0 ;
}
static int vp702x_fe_read_snr ( struct dvb_frontend * fe , u16 * snr )
{
u8 _snr ;
struct vp702x_fe_state * st = fe - > demodulator_priv ;
vp702x_fe_refresh_state ( st ) ;
_snr = ( st - > snr & 0x1f ) * 0xff / 0x1f ;
* snr = ( _snr < < 8 ) | _snr ;
return 0 ;
}
static int vp702x_fe_get_tune_settings ( struct dvb_frontend * fe , struct dvb_frontend_tune_settings * tune )
{
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2005-09-09 13:02:41 -07:00
tune - > min_delay_ms = 2000 ;
return 0 ;
}
2011-12-26 15:57:56 -03:00
static int vp702x_fe_set_frontend ( struct dvb_frontend * fe )
2005-09-09 13:02:41 -07:00
{
2011-12-26 15:57:56 -03:00
struct dtv_frontend_properties * fep = & fe - > dtv_property_cache ;
2005-09-09 13:02:41 -07:00
struct vp702x_fe_state * st = fe - > demodulator_priv ;
2011-03-21 07:19:14 -03:00
struct vp702x_device_state * dst = st - > d - > priv ;
2005-09-09 13:02:41 -07:00
u32 freq = fep - > frequency / 1000 ;
/*CalFrequency*/
/* u16 frequencyRef[16] = { 2, 4, 8, 16, 32, 64, 128, 256, 24, 5, 10, 20, 40, 80, 160, 320 }; */
u64 sr ;
2011-03-21 07:19:10 -03:00
u8 * cmd ;
2011-03-21 07:19:14 -03:00
mutex_lock ( & dst - > buf_mutex ) ;
cmd = dst - > buf ;
memset ( cmd , 0 , 10 ) ;
2005-09-09 13:02:41 -07:00
cmd [ 0 ] = ( freq > > 8 ) & 0x7f ;
cmd [ 1 ] = freq & 0xff ;
cmd [ 2 ] = 1 ; /* divrate == 4 -> frequencyRef[1] -> 1 here */
2011-12-26 15:57:56 -03:00
sr = ( u64 ) ( fep - > symbol_rate / 1000 ) < < 20 ;
2005-09-09 13:02:41 -07:00
do_div ( sr , 88000 ) ;
cmd [ 3 ] = ( sr > > 12 ) & 0xff ;
cmd [ 4 ] = ( sr > > 4 ) & 0xff ;
cmd [ 5 ] = ( sr < < 4 ) & 0xf0 ;
2006-03-25 15:53:38 -03:00
deb_fe ( " setting frontend to: %u -> %u (%x) LNB-based GHz, symbolrate: %d -> %lu (%lx) \n " ,
2011-12-26 15:57:56 -03:00
fep - > frequency , freq , freq , fep - > symbol_rate ,
2006-03-25 15:53:38 -03:00
( unsigned long ) sr , ( unsigned long ) sr ) ;
2005-09-09 13:02:41 -07:00
/* if (fep->inversion == INVERSION_ON)
cmd [ 6 ] | = 0x80 ; */
if ( st - > voltage = = SEC_VOLTAGE_18 )
cmd [ 6 ] | = 0x40 ;
2011-12-26 15:57:56 -03:00
/* if (fep->symbol_rate > 8000000)
2005-09-09 13:02:41 -07:00
cmd [ 6 ] | = 0x20 ;
if ( fep - > frequency < 1531000 )
cmd [ 6 ] | = 0x04 ;
if ( st - > tone_mode = = SEC_TONE_ON )
cmd [ 6 ] | = 0x01 ; */
cmd [ 7 ] = vp702x_chksum ( cmd , 0 , 7 ) ;
st - > status_check_interval = 250 ;
st - > next_status_check = jiffies ;
2011-03-21 07:19:10 -03:00
vp702x_usb_inout_op ( st - > d , cmd , 8 , cmd , 10 , 100 ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:10 -03:00
if ( cmd [ 2 ] = = 0 & & cmd [ 3 ] = = 0 )
2005-09-09 13:02:41 -07:00
deb_fe ( " tuning failed. \n " ) ;
else
deb_fe ( " tuning succeeded. \n " ) ;
2011-03-21 07:19:14 -03:00
mutex_unlock ( & dst - > buf_mutex ) ;
2005-09-09 13:02:41 -07:00
return 0 ;
}
2006-09-19 12:51:43 -03:00
static int vp702x_fe_init ( struct dvb_frontend * fe )
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2006-09-19 12:51:43 -03:00
vp702x_usb_in_op ( st - > d , RESET_TUNER , 0 , 0 , NULL , 0 ) ;
return 0 ;
}
static int vp702x_fe_sleep ( struct dvb_frontend * fe )
{
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2006-09-19 12:51:43 -03:00
return 0 ;
}
2005-09-09 13:02:41 -07:00
static int vp702x_fe_send_diseqc_msg ( struct dvb_frontend * fe ,
2006-01-09 15:25:34 -02:00
struct dvb_diseqc_master_cmd * m )
2005-09-09 13:02:41 -07:00
{
2011-03-21 07:19:10 -03:00
u8 * cmd ;
2007-05-08 09:36:09 -03:00
struct vp702x_fe_state * st = fe - > demodulator_priv ;
2011-03-21 07:19:14 -03:00
struct vp702x_device_state * dst = st - > d - > priv ;
2005-09-09 13:02:41 -07:00
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:14 -03:00
if ( m - > msg_len > 4 )
return - EINVAL ;
mutex_lock ( & dst - > buf_mutex ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:14 -03:00
cmd = dst - > buf ;
2005-09-09 13:02:41 -07:00
cmd [ 1 ] = SET_DISEQC_CMD ;
cmd [ 2 ] = m - > msg_len ;
memcpy ( & cmd [ 3 ] , m - > msg , m - > msg_len ) ;
2011-03-21 07:19:10 -03:00
cmd [ 7 ] = vp702x_chksum ( cmd , 0 , 7 ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:10 -03:00
vp702x_usb_inout_op ( st - > d , cmd , 8 , cmd , 10 , 100 ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:10 -03:00
if ( cmd [ 2 ] = = 0 & & cmd [ 3 ] = = 0 )
2007-05-08 09:36:09 -03:00
deb_fe ( " diseqc cmd failed. \n " ) ;
else
deb_fe ( " diseqc cmd succeeded. \n " ) ;
2011-03-21 07:19:14 -03:00
mutex_unlock ( & dst - > buf_mutex ) ;
return 0 ;
2005-09-09 13:02:41 -07:00
}
2015-06-07 14:53:52 -03:00
static int vp702x_fe_send_diseqc_burst ( struct dvb_frontend * fe ,
enum fe_sec_mini_cmd burst )
2005-09-09 13:02:41 -07:00
{
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2005-09-09 13:02:41 -07:00
return 0 ;
}
2015-06-07 14:53:52 -03:00
static int vp702x_fe_set_tone ( struct dvb_frontend * fe ,
enum fe_sec_tone_mode tone )
2005-09-09 13:02:41 -07:00
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
2011-03-21 07:19:14 -03:00
struct vp702x_device_state * dst = st - > d - > priv ;
2011-03-21 07:19:10 -03:00
u8 * buf ;
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2005-09-09 13:02:41 -07:00
st - > tone_mode = tone ;
if ( tone = = SEC_TONE_ON )
st - > lnb_buf [ 2 ] = 0x02 ;
else
st - > lnb_buf [ 2 ] = 0x00 ;
2011-03-21 07:19:10 -03:00
st - > lnb_buf [ 7 ] = vp702x_chksum ( st - > lnb_buf , 0 , 7 ) ;
2011-03-21 07:19:14 -03:00
mutex_lock ( & dst - > buf_mutex ) ;
buf = dst - > buf ;
2011-03-21 07:19:10 -03:00
memcpy ( buf , st - > lnb_buf , 8 ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:10 -03:00
vp702x_usb_inout_op ( st - > d , buf , 8 , buf , 10 , 100 ) ;
if ( buf [ 2 ] = = 0 & & buf [ 3 ] = = 0 )
2005-09-09 13:02:41 -07:00
deb_fe ( " set_tone cmd failed. \n " ) ;
else
deb_fe ( " set_tone cmd succeeded. \n " ) ;
2011-03-21 07:19:14 -03:00
mutex_unlock ( & dst - > buf_mutex ) ;
2005-09-09 13:02:41 -07:00
return 0 ;
}
2015-06-07 14:53:52 -03:00
static int vp702x_fe_set_voltage ( struct dvb_frontend * fe ,
enum fe_sec_voltage voltage )
2005-09-09 13:02:41 -07:00
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
2011-03-21 07:19:14 -03:00
struct vp702x_device_state * dst = st - > d - > priv ;
2011-03-21 07:19:10 -03:00
u8 * buf ;
2008-04-08 23:20:00 -03:00
deb_fe ( " %s \n " , __func__ ) ;
2005-09-09 13:02:41 -07:00
st - > voltage = voltage ;
if ( voltage ! = SEC_VOLTAGE_OFF )
st - > lnb_buf [ 4 ] = 0x01 ;
else
st - > lnb_buf [ 4 ] = 0x00 ;
2011-03-21 07:19:10 -03:00
st - > lnb_buf [ 7 ] = vp702x_chksum ( st - > lnb_buf , 0 , 7 ) ;
2011-03-21 07:19:14 -03:00
mutex_lock ( & dst - > buf_mutex ) ;
buf = dst - > buf ;
2011-03-21 07:19:10 -03:00
memcpy ( buf , st - > lnb_buf , 8 ) ;
2005-09-09 13:02:41 -07:00
2011-03-21 07:19:10 -03:00
vp702x_usb_inout_op ( st - > d , buf , 8 , buf , 10 , 100 ) ;
if ( buf [ 2 ] = = 0 & & buf [ 3 ] = = 0 )
2005-09-09 13:02:41 -07:00
deb_fe ( " set_voltage cmd failed. \n " ) ;
else
deb_fe ( " set_voltage cmd succeeded. \n " ) ;
2011-03-21 07:19:14 -03:00
mutex_unlock ( & dst - > buf_mutex ) ;
2005-09-09 13:02:41 -07:00
return 0 ;
}
static void vp702x_fe_release ( struct dvb_frontend * fe )
{
struct vp702x_fe_state * st = fe - > demodulator_priv ;
kfree ( st ) ;
}
2016-08-09 18:32:21 -03:00
static const struct dvb_frontend_ops vp702x_fe_ops ;
2005-09-09 13:02:41 -07:00
struct dvb_frontend * vp702x_fe_attach ( struct dvb_usb_device * d )
{
2006-01-11 19:40:56 -02:00
struct vp702x_fe_state * s = kzalloc ( sizeof ( struct vp702x_fe_state ) , GFP_KERNEL ) ;
2005-09-09 13:02:41 -07:00
if ( s = = NULL )
goto error ;
s - > d = d ;
2006-05-14 05:01:31 -03:00
memcpy ( & s - > fe . ops , & vp702x_fe_ops , sizeof ( struct dvb_frontend_ops ) ) ;
2005-09-09 13:02:41 -07:00
s - > fe . demodulator_priv = s ;
s - > lnb_buf [ 1 ] = SET_LNB_POWER ;
s - > lnb_buf [ 3 ] = 0xff ; /* 0=tone burst, 2=data burst, ff=off */
2006-05-12 20:36:24 -03:00
return & s - > fe ;
2005-09-09 13:02:41 -07:00
error :
return NULL ;
}
2016-08-09 18:32:21 -03:00
static const struct dvb_frontend_ops vp702x_fe_ops = {
2011-12-26 15:57:56 -03:00
. delsys = { SYS_DVBS } ,
2005-09-09 13:02:41 -07:00
. info = {
. name = " Twinhan DST-like frontend (VP7021/VP7020) DVB-S " ,
2018-07-05 18:59:36 -04:00
. frequency_min_hz = 950 * MHz ,
. frequency_max_hz = 2150 * MHz ,
. frequency_stepsize_hz = 1 * MHz ,
2005-09-09 13:02:41 -07:00
. symbol_rate_min = 1000000 ,
. symbol_rate_max = 45000000 ,
. symbol_rate_tolerance = 500 , /* ppm */
. 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_QPSK |
FE_CAN_FEC_AUTO
} ,
. release = vp702x_fe_release ,
2006-09-19 12:51:43 -03:00
. init = vp702x_fe_init ,
. sleep = vp702x_fe_sleep ,
2005-09-09 13:02:41 -07:00
2011-12-26 15:57:56 -03:00
. set_frontend = vp702x_fe_set_frontend ,
2005-09-09 13:02:41 -07:00
. get_tune_settings = vp702x_fe_get_tune_settings ,
. read_status = vp702x_fe_read_status ,
. read_ber = vp702x_fe_read_ber ,
. read_signal_strength = vp702x_fe_read_signal_strength ,
. read_snr = vp702x_fe_read_snr ,
. read_ucblocks = vp702x_fe_read_unc_blocks ,
. diseqc_send_master_cmd = vp702x_fe_send_diseqc_msg ,
. diseqc_send_burst = vp702x_fe_send_diseqc_burst ,
. set_tone = vp702x_fe_set_tone ,
. set_voltage = vp702x_fe_set_voltage ,
} ;