mirror of
https://github.com/tbsdtv/linux_media.git
synced 2025-07-23 04:33:26 +02:00
3657 lines
108 KiB
C
3657 lines
108 KiB
C
//SPX-License-Identifier: GPL-2.0-or-later
|
|
/*
|
|
* Montage Technology M88rs6060 demodulator and tuner drivers
|
|
* some code form m88ds3103
|
|
* Copyright (c) 2021 Davin zhang <Davin@tbsdtv.com> www.Turbosight.com
|
|
*
|
|
*/
|
|
#include <media/dvb_math.h>
|
|
|
|
#include "m88rs6060_priv.h"
|
|
#include <linux/mutex.h>
|
|
#define HWTUNE
|
|
|
|
static LIST_HEAD(m88rs6060list);
|
|
static LIST_HEAD(si5351list);
|
|
struct si5351_base{
|
|
struct list_head si5351list;
|
|
struct i2c_adapter *i2c_si5351; // i2c
|
|
struct mutex i2c_mutex_ci;
|
|
|
|
u32 count;
|
|
int clk_port;
|
|
};
|
|
|
|
//for CI
|
|
struct si5351_priv{
|
|
struct si5351_base *base1;
|
|
int clk_port;
|
|
u32 plla_freq;
|
|
u32 pllb_freq;
|
|
};
|
|
struct m88rs6060_base{
|
|
struct list_head m88rs6060list;
|
|
struct mutex i2c_mutex;
|
|
struct i2c_adapter *i2c; // i2c
|
|
u8 adr;
|
|
u32 count;
|
|
// struct i2c_client *tuner_client; //tuner i2c
|
|
|
|
};
|
|
|
|
struct m88rs6060_dev {
|
|
struct regmap *regmap; //demod
|
|
enum fe_status fe_status;
|
|
struct dvb_frontend fe;
|
|
struct m88rs6060_cfg config;
|
|
|
|
bool TsClockChecked; //clock retio
|
|
bool warm; // for the init and download fw
|
|
s32 mclk; /*main mclk */
|
|
|
|
u32 dvbv3_ber; /* for old DVBv3 API read_ber */
|
|
u32 frequecy; //khz
|
|
u64 post_bit_error;
|
|
u64 post_bit_count;
|
|
struct m88rs6060_base *base;
|
|
struct si5351_priv *priv;
|
|
bool newTP;
|
|
|
|
};
|
|
|
|
static u16 mes_log10[] = {
|
|
0, 3010, 4771, 6021, 6990, 7781, 8451, 9031, 9542, 10000,
|
|
10414, 10792, 11139, 11461, 11761, 12041, 12304, 12553, 12788, 13010,
|
|
13222, 13424, 13617, 13802, 13979, 14150, 14314, 14472, 14624, 14771,
|
|
14914, 15052, 15185, 15315, 15441, 15563, 15682, 15798, 15911, 16021,
|
|
16128, 16232, 16335, 16435, 16532, 16628, 16721, 16812, 16902, 16990,
|
|
17076, 17160, 17243, 17324, 17404, 17482, 17559, 17634, 17709, 17782,
|
|
17853, 17924, 17993, 18062, 18129, 18195, 18261, 18325, 18388, 18451,
|
|
18513, 18573, 18633, 18692, 18751, 18808, 18865, 18921, 18976, 19031
|
|
};
|
|
|
|
static u16 mes_loge[] = {
|
|
0, 6931, 10986, 13863, 16094, 17918, 19459, 20794, 21972, 23026,
|
|
23979, 24849, 25649, 26391, 27081, 27726, 28332, 28904, 29444, 29957,
|
|
30445, 30910, 31355, 31781, 32189, 32581, 32958, 33322, 33673, 34012,
|
|
34340, 34657
|
|
};
|
|
|
|
static struct MT_FE_PLS_INFO mPLSInfoTable[] =
|
|
{
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0x00, TRUE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, TRUE, 0},
|
|
{0x01, TRUE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, TRUE, 0},
|
|
{0x02, TRUE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, TRUE, 1},
|
|
{0x03, TRUE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, TRUE, 1},
|
|
{0x04, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_4, FALSE, FALSE, 0},
|
|
{0x05, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_4, TRUE, FALSE, 0},
|
|
{0x06, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_4, FALSE, FALSE, 1},
|
|
{0x07, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_4, TRUE, FALSE, 1},
|
|
{0x08, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_3, FALSE, FALSE, 0},
|
|
{0x09, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_3, TRUE, FALSE, 0},
|
|
{0x0A, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_3, FALSE, FALSE, 1},
|
|
{0x0B, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_3, TRUE, FALSE, 1},
|
|
{0x0C, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_5, FALSE, FALSE, 0},
|
|
{0x0D, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_5, TRUE, FALSE, 0},
|
|
{0x0E, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_5, FALSE, FALSE, 1},
|
|
{0x0F, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_5, TRUE, FALSE, 1},
|
|
{0x10, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_2, FALSE, FALSE, 0},
|
|
{0x11, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_2, TRUE, FALSE, 0},
|
|
{0x12, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_2, FALSE, FALSE, 1},
|
|
{0x13, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_1_2, TRUE, FALSE, 1},
|
|
{0x14, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_5, FALSE, FALSE, 0},
|
|
{0x15, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_5, TRUE, FALSE, 0},
|
|
{0x16, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_5, FALSE, FALSE, 1},
|
|
{0x17, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_5, TRUE, FALSE, 1},
|
|
{0x18, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_3, FALSE, FALSE, 0},
|
|
{0x19, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_3, TRUE, FALSE, 0},
|
|
{0x1A, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_3, FALSE, FALSE, 1},
|
|
{0x1B, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_2_3, TRUE, FALSE, 1},
|
|
{0x1C, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_4, FALSE, FALSE, 0},
|
|
{0x1D, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_4, TRUE, FALSE, 0},
|
|
{0x1E, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_4, FALSE, FALSE, 1},
|
|
{0x1F, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_3_4, TRUE, FALSE, 1},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0x20, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_4_5, FALSE, FALSE, 0},
|
|
{0x21, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_4_5, TRUE, FALSE, 0},
|
|
{0x22, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_4_5, FALSE, FALSE, 1},
|
|
{0x23, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_4_5, TRUE, FALSE, 1},
|
|
{0x24, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_5_6, FALSE, FALSE, 0},
|
|
{0x25, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_5_6, TRUE, FALSE, 0},
|
|
{0x26, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_5_6, FALSE, FALSE, 1},
|
|
{0x27, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_5_6, TRUE, FALSE, 1},
|
|
{0x28, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_8_9, FALSE, FALSE, 0},
|
|
{0x29, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_8_9, TRUE, FALSE, 0},
|
|
{0x2A, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_8_9, FALSE, FALSE, 1},
|
|
{0x2B, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_8_9, TRUE, FALSE, 1},
|
|
{0x2C, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_9_10, FALSE, FALSE, 0},
|
|
{0x2D, TRUE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_9_10, TRUE, FALSE, 0},
|
|
{0x2E, FALSE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_9_10, FALSE, FALSE, 1},
|
|
{0x2F, FALSE, MtFeType_DvbS2, MtFeModMode_Qpsk, MtFeCodeRate_9_10, TRUE, FALSE, 1},
|
|
{0x30, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_5, FALSE, FALSE, 0},
|
|
{0x31, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_5, TRUE, FALSE, 0},
|
|
{0x32, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_5, FALSE, FALSE, 1},
|
|
{0x33, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_5, TRUE, FALSE, 1},
|
|
{0x34, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_2_3, FALSE, FALSE, 0},
|
|
{0x35, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_2_3, TRUE, FALSE, 0},
|
|
{0x36, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_2_3, FALSE, FALSE, 1},
|
|
{0x37, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_2_3, TRUE, FALSE, 1},
|
|
{0x38, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_4, FALSE, FALSE, 0},
|
|
{0x39, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_4, TRUE, FALSE, 0},
|
|
{0x3A, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_4, FALSE, FALSE, 1},
|
|
{0x3B, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_3_4, TRUE, FALSE, 1},
|
|
{0x3C, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_5_6, FALSE, FALSE, 0},
|
|
{0x3D, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_5_6, TRUE, FALSE, 0},
|
|
{0x3E, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_5_6, FALSE, FALSE, 1},
|
|
{0x3F, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_5_6, TRUE, FALSE, 1},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0x40, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_8_9, FALSE, FALSE, 0},
|
|
{0x41, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_8_9, TRUE, FALSE, 0},
|
|
{0x42, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_8_9, FALSE, FALSE, 1},
|
|
{0x43, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_8_9, TRUE, FALSE, 1},
|
|
{0x44, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_9_10, FALSE, FALSE, 0},
|
|
{0x45, TRUE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_9_10, TRUE, FALSE, 0},
|
|
{0x46, FALSE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_9_10, FALSE, FALSE, 1},
|
|
{0x47, FALSE, MtFeType_DvbS2, MtFeModMode_8psk, MtFeCodeRate_9_10, TRUE, FALSE, 1},
|
|
{0x48, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_2_3, FALSE, FALSE, 0},
|
|
{0x49, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_2_3, TRUE, FALSE, 0},
|
|
{0x4A, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_2_3, FALSE, FALSE, 1},
|
|
{0x4B, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_2_3, TRUE, FALSE, 1},
|
|
{0x4C, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_3_4, FALSE, FALSE, 0},
|
|
{0x4D, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_3_4, TRUE, FALSE, 0},
|
|
{0x4E, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_3_4, FALSE, FALSE, 1},
|
|
{0x4F, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_3_4, TRUE, FALSE, 1},
|
|
{0x50, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_4_5, FALSE, FALSE, 0},
|
|
{0x51, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_4_5, TRUE, FALSE, 0},
|
|
{0x52, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_4_5, FALSE, FALSE, 1},
|
|
{0x53, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_4_5, TRUE, FALSE, 1},
|
|
{0x54, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_5_6, FALSE, FALSE, 0},
|
|
{0x55, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_5_6, TRUE, FALSE, 0},
|
|
{0x56, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_5_6, FALSE, FALSE, 1},
|
|
{0x57, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_5_6, TRUE, FALSE, 1},
|
|
{0x58, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_8_9, FALSE, FALSE, 0},
|
|
{0x59, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_8_9, TRUE, FALSE, 0},
|
|
{0x5A, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_8_9, FALSE, FALSE, 1},
|
|
{0x5B, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_8_9, TRUE, FALSE, 1},
|
|
{0x5C, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_9_10, FALSE, FALSE, 0},
|
|
{0x5D, TRUE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_9_10, TRUE, FALSE, 0},
|
|
{0x5E, FALSE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_9_10, FALSE, FALSE, 1},
|
|
{0x5F, FALSE, MtFeType_DvbS2, MtFeModMode_16Apsk, MtFeCodeRate_9_10, TRUE, FALSE, 1},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0x60, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_3_4, FALSE, FALSE, 0},
|
|
{0x61, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_3_4, TRUE, FALSE, 0},
|
|
{0x62, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_3_4, FALSE, FALSE, 1},
|
|
{0x63, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_3_4, TRUE, FALSE, 1},
|
|
{0x64, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_4_5, FALSE, FALSE, 0},
|
|
{0x65, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_4_5, TRUE, FALSE, 0},
|
|
{0x66, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_4_5, FALSE, FALSE, 1},
|
|
{0x67, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_4_5, TRUE, FALSE, 1},
|
|
{0x68, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_5_6, FALSE, FALSE, 0},
|
|
{0x69, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_5_6, TRUE, FALSE, 0},
|
|
{0x6A, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_5_6, FALSE, FALSE, 1},
|
|
{0x6B, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_5_6, TRUE, FALSE, 1},
|
|
{0x6C, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_8_9, FALSE, FALSE, 0},
|
|
{0x6D, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_8_9, TRUE, FALSE, 0},
|
|
{0x6E, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_8_9, FALSE, FALSE, 1},
|
|
{0x6F, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_8_9, TRUE, FALSE, 1},
|
|
{0x70, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_9_10, FALSE, FALSE, 0},
|
|
{0x71, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_9_10, TRUE, FALSE, 0},
|
|
{0x72, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_9_10, FALSE, FALSE, 1},
|
|
{0x73, TRUE, MtFeType_DvbS2, MtFeModMode_32Apsk, MtFeCodeRate_9_10, TRUE, FALSE, 1},
|
|
{0x74, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0x75, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0x76, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 1},
|
|
{0x77, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 1},
|
|
{0x78, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0x79, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0x7A, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 1},
|
|
{0x7B, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 1},
|
|
{0x7C, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0x7D, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0x7E, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 1},
|
|
{0x7F, FALSE, MtFeType_DvbS2, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 1},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0x80, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0x81, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0x82, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0x83, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0x84, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_13_45, FALSE, FALSE, 0},
|
|
{0x85, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_13_45, TRUE, FALSE, 0},
|
|
{0x86, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_9_20, FALSE, FALSE, 0},
|
|
{0x87, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_9_20, TRUE, FALSE, 0},
|
|
{0x88, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_11_20, FALSE, FALSE, 0},
|
|
{0x89, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_11_20, TRUE, FALSE, 0},
|
|
{0x8A, TRUE, MtFeType_DvbS2X, MtFeModMode_8Apsk_L, MtFeCodeRate_5_9, FALSE, FALSE, 0},
|
|
{0x8B, TRUE, MtFeType_DvbS2X, MtFeModMode_8Apsk_L, MtFeCodeRate_5_9, TRUE, FALSE, 0},
|
|
{0x8C, TRUE, MtFeType_DvbS2X, MtFeModMode_8Apsk_L, MtFeCodeRate_26_45, FALSE, FALSE, 0},
|
|
{0x8D, TRUE, MtFeType_DvbS2X, MtFeModMode_8Apsk_L, MtFeCodeRate_26_45, TRUE, FALSE, 0},
|
|
{0x8E, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_23_36, FALSE, FALSE, 0},
|
|
{0x8F, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_23_36, TRUE, FALSE, 0},
|
|
{0x90, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_25_36, FALSE, FALSE, 0},
|
|
{0x91, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_25_36, TRUE, FALSE, 0},
|
|
{0x92, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_13_18, FALSE, FALSE, 0},
|
|
{0x93, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_13_18, TRUE, FALSE, 0},
|
|
{0x94, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_1_2, FALSE, FALSE, 0},
|
|
{0x95, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_1_2, TRUE, FALSE, 0},
|
|
{0x96, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_8_15, FALSE, FALSE, 0},
|
|
{0x97, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_8_15, TRUE, FALSE, 0},
|
|
{0x98, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_5_9, FALSE, FALSE, 0},
|
|
{0x99, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_5_9, TRUE, FALSE, 0},
|
|
{0x9A, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_26_45, FALSE, FALSE, 0},
|
|
{0x9B, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_26_45, TRUE, FALSE, 0},
|
|
{0x9C, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_3_5, FALSE, FALSE, 0},
|
|
{0x9D, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_3_5, TRUE, FALSE, 0},
|
|
{0x9E, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_3_5, FALSE, FALSE, 0},
|
|
{0x9F, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_3_5, TRUE, FALSE, 0},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0xA0, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_28_45, FALSE, FALSE, 0},
|
|
{0xA1, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_28_45, TRUE, FALSE, 0},
|
|
{0xA2, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_23_36, FALSE, FALSE, 0},
|
|
{0xA3, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_23_36, TRUE, FALSE, 0},
|
|
{0xA4, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_2_3, FALSE, FALSE, 0},
|
|
{0xA5, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk_L, MtFeCodeRate_2_3, TRUE, FALSE, 0},
|
|
{0xA6, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_25_36, FALSE, FALSE, 0},
|
|
{0xA7, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_25_36, TRUE, FALSE, 0},
|
|
{0xA8, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_13_18, FALSE, FALSE, 0},
|
|
{0xA9, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_13_18, TRUE, FALSE, 0},
|
|
{0xAA, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_7_9, FALSE, FALSE, 0},
|
|
{0xAB, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_7_9, TRUE, FALSE, 0},
|
|
{0xAC, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_77_90, FALSE, FALSE, 0},
|
|
{0xAD, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_77_90, TRUE, FALSE, 0},
|
|
{0xAE, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk_L, MtFeCodeRate_2_3, FALSE, FALSE, 0},
|
|
{0xAF, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk_L, MtFeCodeRate_2_3, TRUE, FALSE, 0},
|
|
{0xB0, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xB1, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0xB2, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_32_45, FALSE, FALSE, 0},
|
|
{0xB3, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_32_45, TRUE, FALSE, 0},
|
|
{0xB4, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_11_15, FALSE, FALSE, 0},
|
|
{0xB5, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_11_15, TRUE, FALSE, 0},
|
|
{0xB6, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_7_9, FALSE, FALSE, 0},
|
|
{0xB7, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_7_9, TRUE, FALSE, 0},
|
|
{0xB8, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk_L, MtFeCodeRate_32_45, FALSE, FALSE, 0},
|
|
{0xB9, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk_L, MtFeCodeRate_32_45, TRUE, FALSE, 0},
|
|
{0xBA, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_11_15, FALSE, FALSE, 0},
|
|
{0xBB, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_11_15, TRUE, FALSE, 0},
|
|
{0xBC, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xBD, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0xBE, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_7_9, FALSE, FALSE, 0},
|
|
{0xBF, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0xC0, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xC1, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0xC2, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_4_5, FALSE, FALSE, 0},
|
|
{0xC3, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_4_5, TRUE, FALSE, 0},
|
|
{0xC4, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xC5, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0xC6, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_5_6, FALSE, FALSE, 0},
|
|
{0xC7, TRUE, MtFeType_DvbS2X, MtFeModMode_64Apsk, MtFeCodeRate_5_6, TRUE, FALSE, 0},
|
|
{0xC8, TRUE, MtFeType_DvbS2X, MtFeModMode_128Apsk, MtFeCodeRate_3_4, FALSE, FALSE, 0},
|
|
{0xC9, TRUE, MtFeType_DvbS2X, MtFeModMode_128Apsk, MtFeCodeRate_3_4, TRUE, FALSE, 0},
|
|
{0xCA, TRUE, MtFeType_DvbS2X, MtFeModMode_128Apsk, MtFeCodeRate_7_9, FALSE, FALSE, 0},
|
|
{0xCB, TRUE, MtFeType_DvbS2X, MtFeModMode_128Apsk, MtFeCodeRate_7_9, TRUE, FALSE, 0},
|
|
{0xCC, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_29_45, FALSE, FALSE, 0},
|
|
{0xCD, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_29_45, TRUE, FALSE, 0},
|
|
{0xCE, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_2_3, FALSE, FALSE, 0},
|
|
{0xCF, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_2_3, TRUE, FALSE, 0},
|
|
{0xD0, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_31_45, FALSE, FALSE, 0},
|
|
{0xD1, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_31_45, TRUE, FALSE, 0},
|
|
{0xD2, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk, MtFeCodeRate_32_45, FALSE, FALSE, 0},
|
|
{0xD3, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk, MtFeCodeRate_32_45, TRUE, FALSE, 0},
|
|
{0xD4, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_11_15, FALSE, FALSE, 0},
|
|
{0xD5, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk_L, MtFeCodeRate_11_15, TRUE, FALSE, 0},
|
|
{0xD6, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk, MtFeCodeRate_3_4, FALSE, FALSE, 0},
|
|
{0xD7, TRUE, MtFeType_DvbS2X, MtFeModMode_256Apsk, MtFeCodeRate_3_4, TRUE, FALSE, 1},
|
|
{0xD8, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_11_45, FALSE, FALSE, 1},
|
|
{0xD9, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_11_45, TRUE, FALSE, 1},
|
|
{0xDA, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_4_15, FALSE, FALSE, 1},
|
|
{0xDB, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_4_15, TRUE, FALSE, 1},
|
|
{0xDC, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_14_45, FALSE, FALSE, 1},
|
|
{0xDD, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_14_45, TRUE, FALSE, 1},
|
|
{0xDE, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_7_15, FALSE, FALSE, 1},
|
|
{0xDF, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_7_15, TRUE, FALSE, 1},
|
|
// PLS Code, Valid, DVB Type, Mod Mode, Code Rate, Pilot, Dummy Frames, Frame Length
|
|
{0xE0, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_8_15, FALSE, FALSE, 1},
|
|
{0xE1, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_8_15, TRUE, FALSE, 1},
|
|
{0xE2, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_32_45, FALSE, FALSE, 1},
|
|
{0xE3, TRUE, MtFeType_DvbS2X, MtFeModMode_Qpsk, MtFeCodeRate_32_45, TRUE, FALSE, 1},
|
|
{0xE4, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_7_15, FALSE, FALSE, 1},
|
|
{0xE5, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_7_15, TRUE, FALSE, 1},
|
|
{0xE6, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_8_15, FALSE, FALSE, 1},
|
|
{0xE7, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_8_15, TRUE, FALSE, 1},
|
|
{0xE8, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_26_45, FALSE, FALSE, 1},
|
|
{0xE9, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_26_45, TRUE, FALSE, 1},
|
|
{0xEA, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_32_45, FALSE, FALSE, 1},
|
|
{0xEB, TRUE, MtFeType_DvbS2X, MtFeModMode_8psk, MtFeCodeRate_32_45, TRUE, FALSE, 1},
|
|
{0xEC, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_7_15, FALSE, FALSE, 1},
|
|
{0xED, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_7_15, TRUE, FALSE, 1},
|
|
{0xEE, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_8_15, FALSE, FALSE, 1},
|
|
{0xEF, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_8_15, TRUE, FALSE, 1},
|
|
{0xF0, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_26_45, FALSE, FALSE, 1},
|
|
{0xF1, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_26_45, TRUE, FALSE, 1},
|
|
{0xF2, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_3_5, FALSE, FALSE, 1},
|
|
{0xF3, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_3_5, TRUE, FALSE, 1},
|
|
{0xF4, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_32_45, FALSE, FALSE, 1},
|
|
{0xF5, TRUE, MtFeType_DvbS2X, MtFeModMode_16Apsk, MtFeCodeRate_32_45, TRUE, FALSE, 1},
|
|
{0xF6, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_2_3, FALSE, FALSE, 1},
|
|
{0xF7, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_2_3, TRUE, FALSE, 1},
|
|
{0xF8, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_32_45, FALSE, FALSE, 1},
|
|
{0xF9, TRUE, MtFeType_DvbS2X, MtFeModMode_32Apsk, MtFeCodeRate_32_45, TRUE, FALSE, 1},
|
|
{0xFA, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xFB, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0xFC, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xFD, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0},
|
|
{0xFE, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, FALSE, FALSE, 0},
|
|
{0xFF, FALSE, MtFeType_DvbS2X, MtFeModMode_Undef, MtFeCodeRate_Undef, TRUE, FALSE, 0}
|
|
};
|
|
|
|
static int si5351_write(struct si5351_priv *priv,u8 reg,u8 data)
|
|
{
|
|
struct i2c_adapter *i2c = priv->base1->i2c_si5351;
|
|
u8 buf[] = { reg, data };
|
|
u8 val;
|
|
int ret;
|
|
struct i2c_msg msg = {
|
|
.addr = SI5351_BUS_BASE_ADDR,.flags = 0,.buf = buf,.len = 2
|
|
};
|
|
|
|
ret = i2c_transfer(i2c, &msg, 1);
|
|
if (ret != 1) {
|
|
dev_err(&i2c->dev,
|
|
"si5351(ret=%i, reg=0x%02x, value=0x%02x)\n",
|
|
ret, reg, data);
|
|
return -EREMOTEIO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int si5351_write_bulk(struct si5351_priv *priv,u8 reg, u8 len,u8*data)
|
|
|
|
{
|
|
struct i2c_adapter *i2c = priv->base1->i2c_si5351;
|
|
u8 buf[80];
|
|
u8 val;
|
|
int ret;
|
|
|
|
buf[0] = reg;
|
|
memcpy(&buf[1],data,len);
|
|
|
|
struct i2c_msg msg = {
|
|
.addr = SI5351_BUS_BASE_ADDR,.flags = 0,.buf = buf,.len = len+1
|
|
};
|
|
|
|
ret = i2c_transfer(i2c, &msg, 1);
|
|
if (ret != 1) {
|
|
dev_err(&i2c->dev,
|
|
"si5351(ret=%i, reg=0x%02x, value=0x%02x)\n",
|
|
ret, reg, data);
|
|
return -EREMOTEIO;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static u8 si5351_read(struct si5351_priv *priv,u8 reg,u8 *data)
|
|
|
|
{
|
|
struct i2c_adapter *i2c = priv->base1->i2c_si5351;
|
|
int ret;
|
|
unsigned val;
|
|
u8 b0[] = { reg };
|
|
struct i2c_msg msg[] = {
|
|
{
|
|
.addr = SI5351_BUS_BASE_ADDR,
|
|
.flags = 0,
|
|
.buf = b0,
|
|
.len = 1},
|
|
{
|
|
.addr = SI5351_BUS_BASE_ADDR,
|
|
.flags = I2C_M_RD,
|
|
.buf = data,
|
|
.len = 1}
|
|
};
|
|
|
|
ret = i2c_transfer(i2c, msg, 2);
|
|
if (ret != 2) {
|
|
dev_err(&i2c->dev, "si5351 (ret=%d, reg=0x%02x)\n",
|
|
ret, reg);
|
|
return -EREMOTEIO;
|
|
}
|
|
|
|
dev_dbg(&i2c->dev, "si5351 reg 0x%02x, value 0x%02x\n",
|
|
reg, *data);
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Calculate best rational approximation for a given fraction
|
|
* taking into account restricted register size, e.g. to find
|
|
* appropriate values for a pll with 5 bit denominator and
|
|
* 8 bit numerator register fields, trying to set up with a
|
|
* frequency ratio of 3.1415, one would say:
|
|
*
|
|
* rational_best_approximation(31415, 10000,
|
|
* (1 << 8) - 1, (1 << 5) - 1, &n, &d);
|
|
*
|
|
* you may look at given_numerator as a fixed point number,
|
|
* with the fractional part size described in given_denominator.
|
|
*
|
|
* for theoretical background, see:
|
|
* http://en.wikipedia.org/wiki/Continued_fraction
|
|
*/
|
|
static void rational_best_approximation(
|
|
unsigned long given_numerator, unsigned long given_denominator,
|
|
unsigned long max_numerator, unsigned long max_denominator,
|
|
unsigned long *best_numerator, unsigned long *best_denominator)
|
|
{
|
|
|
|
unsigned long n, d, n0, d0, n1, d1;
|
|
n = given_numerator;
|
|
d = given_denominator;
|
|
n0 = d1 = 0;
|
|
n1 = d0 = 1;
|
|
for (;;) {
|
|
unsigned long t, a;
|
|
if ((n1 > max_numerator) || (d1 > max_denominator)) {
|
|
n1 = n0;
|
|
d1 = d0;
|
|
break;
|
|
}
|
|
if (d == 0)
|
|
break;
|
|
|
|
t = d;
|
|
a = n / d;
|
|
d = n % d;
|
|
n = t;
|
|
t = n0 + a * n1;
|
|
n0 = n1;
|
|
n1 = t;
|
|
t = d0 + a * d1;
|
|
d0 = d1;
|
|
d1 = t;
|
|
}
|
|
|
|
*best_numerator = n1;
|
|
*best_denominator = d1;
|
|
}
|
|
|
|
static u32 pll_calc(u32 freq, struct Si5351RegSet *reg, int correction)
|
|
|
|
{
|
|
|
|
u32 ref_freq = SI5351_XTAL_FREQ;
|
|
u32 rfrac, denom, a, p1, p2, p3;
|
|
unsigned long b, c;
|
|
u64 lltmp;
|
|
|
|
/* Factor calibration value into nominal crystal frequency */
|
|
/* Measured in parts-per-ten million */
|
|
ref_freq += (u32)((correction / 10000000) * ref_freq);
|
|
|
|
/* PLL bounds checking */
|
|
if (freq < SI5351_PLL_VCO_MIN)
|
|
freq = SI5351_PLL_VCO_MIN;
|
|
if (freq > SI5351_PLL_VCO_MAX)
|
|
freq = SI5351_PLL_VCO_MAX;
|
|
|
|
/* Determine integer part of feedback equation */
|
|
a = freq / ref_freq;
|
|
if (a < SI5351_PLL_A_MIN)
|
|
freq = ref_freq * SI5351_PLL_A_MIN;
|
|
if (a > SI5351_PLL_A_MAX)
|
|
freq = ref_freq * SI5351_PLL_A_MAX;
|
|
|
|
/* find best approximation for b/c = fVCO mod fIN */
|
|
denom = 1000L * 1000L;
|
|
lltmp = freq % ref_freq;
|
|
lltmp *= denom;
|
|
do_div(lltmp, ref_freq);
|
|
rfrac = (u32)lltmp;
|
|
|
|
b = 0;
|
|
c = 1;
|
|
if (rfrac)
|
|
rational_best_approximation(rfrac, denom, \
|
|
SI5351_PLL_B_MAX, SI5351_PLL_C_MAX, &b, &c);
|
|
|
|
/* calculate parameters */
|
|
p3 = c;
|
|
p2 = (128 * b) % c;
|
|
p1 = 128 * a;
|
|
p1 += (128 * b / c);
|
|
p1 -= 512;
|
|
|
|
/* recalculate rate by fIN * (a + b/c) */
|
|
lltmp = ref_freq;
|
|
lltmp *= b;
|
|
do_div(lltmp, c);
|
|
|
|
freq = (u32)lltmp;
|
|
freq += ref_freq * a;
|
|
|
|
reg->p1 = p1;
|
|
reg->p2 = p2;
|
|
reg->p3 = p3;
|
|
|
|
return freq;
|
|
}
|
|
/*
|
|
* si5351_set_pll(uint32_t pll_freq, enum si5351_pll target_pll)
|
|
*
|
|
* Set the specified PLL to a specific oscillation frequency
|
|
*
|
|
* pll_freq - Desired PLL frequency
|
|
* target_pll - Which PLL to set
|
|
* (use the si5351_pll enum)
|
|
*/
|
|
void si5351_set_pll(struct si5351_priv *priv,u32 pll_freq, enum si5351_pll target_pll)
|
|
{
|
|
|
|
struct Si5351RegSet pll_reg;
|
|
|
|
pll_calc(pll_freq, &pll_reg, 0);
|
|
/* Derive the register values to write */
|
|
/* Prepare an array for parameters to be written to */
|
|
|
|
u8 params[30];
|
|
u8 i = 0;
|
|
u8 temp;
|
|
|
|
/* Registers 26-27 */
|
|
temp = ((pll_reg.p3 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
temp = (u8)(pll_reg.p3 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Register 28 */
|
|
temp = (u8)((pll_reg.p1 >> 16) & 0x03);
|
|
params[i++] = temp;
|
|
|
|
/* Registers 29-30 */
|
|
temp = (u8)((pll_reg.p1 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
temp = (u8)(pll_reg.p1 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Register 31 */
|
|
temp = (u8)((pll_reg.p3 >> 12) & 0xF0);
|
|
temp += (u8)((pll_reg.p2 >> 16) & 0x0F);
|
|
params[i++] = temp;
|
|
|
|
/* Registers 32-33 */
|
|
temp = (u8)((pll_reg.p2 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
temp = (u8)(pll_reg.p2 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Write the parameters */
|
|
if(target_pll == SI5351_PLLA)
|
|
{
|
|
si5351_write_bulk(priv,SI5351_PLLA_PARAMETERS, i + 1, params);
|
|
}
|
|
else if(target_pll == SI5351_PLLB)
|
|
{
|
|
si5351_write_bulk(priv,SI5351_PLLB_PARAMETERS, i + 1, params);
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* si5351_clock_enable(enum si5351_clock clk, uint8_t enable)
|
|
*
|
|
* Enable or disable a chosen clock
|
|
* clk - Clock output
|
|
* (use the si5351_clock enum)
|
|
* enable - Set to 1 to enable, 0 to disable
|
|
*/
|
|
static void si5351_clock_enable(struct si5351_priv *priv,enum si5351_clock clk, u8 enable)
|
|
{
|
|
|
|
u8 reg_val;
|
|
|
|
if(si5351_read(priv,SI5351_OUTPUT_ENABLE_CTRL, ®_val) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(enable == 1)
|
|
{
|
|
reg_val &= ~(1<<(u8)clk);
|
|
}
|
|
else
|
|
{
|
|
reg_val |= (1<<(u8)clk);
|
|
}
|
|
|
|
si5351_write(priv,SI5351_OUTPUT_ENABLE_CTRL, reg_val);
|
|
|
|
}
|
|
|
|
/*
|
|
* si5351_drive_strength(enum si5351_clock clk, enum si5351_drive drive)
|
|
*
|
|
* Sets the drive strength of the specified clock output
|
|
*
|
|
* clk - Clock output
|
|
* (use the si5351_clock enum)
|
|
* drive - Desired drive level
|
|
* (use the si5351_drive enum)
|
|
*/
|
|
static void si5351_drive_strength(struct si5351_priv *priv, enum si5351_clock clk, enum si5351_drive drive)
|
|
{
|
|
u8 reg_val;
|
|
|
|
const u8 mask = 0x03;
|
|
|
|
if(si5351_read(priv,SI5351_CLK0_CTRL + (u8)clk, ®_val) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
switch(drive)
|
|
{
|
|
case SI5351_DRIVE_2MA:
|
|
reg_val &= ~(mask);
|
|
reg_val |= 0x00;
|
|
break;
|
|
case SI5351_DRIVE_4MA:
|
|
reg_val &= ~(mask);
|
|
reg_val |= 0x01;
|
|
break;
|
|
case SI5351_DRIVE_6MA:
|
|
reg_val &= ~(mask);
|
|
reg_val |= 0x02;
|
|
break;
|
|
case SI5351_DRIVE_8MA:
|
|
reg_val &= ~(mask);
|
|
reg_val |= 0x03;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
si5351_write(priv,SI5351_CLK0_CTRL + (u8)clk, reg_val);
|
|
}
|
|
|
|
|
|
static u32 multisynth_calc(u32 freq, struct Si5351RegSet *reg)
|
|
{
|
|
u32 pll_freq;
|
|
u64 lltmp;
|
|
u32 a, b, c, p1, p2, p3;
|
|
u8 divby4;
|
|
|
|
/* Multisynth bounds checking */
|
|
if (freq > SI5351_MULTISYNTH_MAX_FREQ)
|
|
freq = SI5351_MULTISYNTH_MAX_FREQ;
|
|
if (freq < SI5351_MULTISYNTH_MIN_FREQ)
|
|
freq = SI5351_MULTISYNTH_MIN_FREQ;
|
|
|
|
divby4 = 0;
|
|
if (freq > SI5351_MULTISYNTH_DIVBY4_FREQ)
|
|
divby4 = 1;
|
|
|
|
/* Find largest integer divider for max */
|
|
/* VCO frequency and given target frequency */
|
|
if (divby4 == 0)
|
|
{
|
|
lltmp = SI5351_PLL_VCO_MAX;
|
|
do_div(lltmp, freq);
|
|
a = (u32)lltmp;
|
|
}
|
|
else
|
|
a = 4;
|
|
|
|
b = 0;
|
|
c = 1;
|
|
pll_freq = a * freq;
|
|
|
|
/* Recalculate output frequency by fOUT = fIN / (a + b/c) */
|
|
lltmp = pll_freq;
|
|
lltmp *= c;
|
|
do_div(lltmp, a * c + b);
|
|
freq = (unsigned long)lltmp;
|
|
|
|
/* Calculate parameters */
|
|
if (divby4)
|
|
{
|
|
p3 = 1;
|
|
p2 = 0;
|
|
p1 = 0;
|
|
}
|
|
else
|
|
{
|
|
p3 = c;
|
|
p2 = (128 * b) % c;
|
|
p1 = 128 * a;
|
|
p1 += (128 * b / c);
|
|
p1 -= 512;
|
|
}
|
|
|
|
reg->p1 = p1;
|
|
reg->p2 = p2;
|
|
reg->p3 = p3;
|
|
|
|
return pll_freq;
|
|
|
|
}
|
|
|
|
static u32 multisynth_recalc(u32 freq, u32 pll_freq, struct Si5351RegSet *reg)
|
|
{
|
|
|
|
u64 lltmp;
|
|
u32 rfrac, denom, a, p1, p2, p3;
|
|
unsigned long b,c;
|
|
u8 divby4;
|
|
|
|
/* Multisynth bounds checking */
|
|
if (freq > SI5351_MULTISYNTH_MAX_FREQ)
|
|
freq = SI5351_MULTISYNTH_MAX_FREQ;
|
|
if (freq < SI5351_MULTISYNTH_MIN_FREQ)
|
|
freq = SI5351_MULTISYNTH_MIN_FREQ;
|
|
|
|
divby4 = 0;
|
|
if (freq > SI5351_MULTISYNTH_DIVBY4_FREQ)
|
|
divby4 = 1;
|
|
|
|
/* Determine integer part of feedback equation */
|
|
a = pll_freq / freq;
|
|
/* TODO: not sure this is correct */
|
|
if (a < SI5351_MULTISYNTH_A_MIN)
|
|
freq = pll_freq / SI5351_MULTISYNTH_A_MIN;
|
|
if (a > SI5351_MULTISYNTH_A_MAX)
|
|
freq = pll_freq / SI5351_MULTISYNTH_A_MAX;
|
|
|
|
/* find best approximation for b/c */
|
|
denom = 1000L * 1000L;
|
|
lltmp = pll_freq % freq;
|
|
lltmp *= denom;
|
|
do_div(lltmp, freq);
|
|
rfrac = (u32)lltmp;
|
|
|
|
b = 0;
|
|
c = 1;
|
|
if (rfrac)
|
|
rational_best_approximation(rfrac, denom, \
|
|
SI5351_MULTISYNTH_B_MAX, SI5351_MULTISYNTH_C_MAX, &b, &c);
|
|
|
|
/* Recalculate output frequency by fOUT = fIN / (a + b/c) */
|
|
lltmp = pll_freq;
|
|
lltmp *= c;
|
|
do_div(lltmp, a * c + b);
|
|
freq = (unsigned long)lltmp;
|
|
|
|
/* Calculate parameters */
|
|
if (divby4)
|
|
{
|
|
p3 = 1;
|
|
p2 = 0;
|
|
p1 = 0;
|
|
}
|
|
else
|
|
{
|
|
p3 = c;
|
|
p2 = (128 * b) % c;
|
|
p1 = 128 * a;
|
|
p1 += (128 * b / c);
|
|
p1 -= 512;
|
|
}
|
|
|
|
reg->p1 = p1;
|
|
reg->p2 = p2;
|
|
reg->p3 = p3;
|
|
|
|
return freq;
|
|
}
|
|
|
|
static void si5351_set_ms_source(struct si5351_priv *priv, enum si5351_clock clk, enum si5351_pll pll)
|
|
{
|
|
u8 reg_val = 0x0c;
|
|
u8 reg_val2;
|
|
|
|
if(si5351_read(priv,SI5351_CLK0_CTRL + (u8)clk, ®_val2) != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if(pll == SI5351_PLLA)
|
|
{
|
|
reg_val &= ~(SI5351_CLK_PLL_SELECT);
|
|
}
|
|
else if(pll == SI5351_PLLB)
|
|
{
|
|
reg_val |= SI5351_CLK_PLL_SELECT;
|
|
}
|
|
si5351_write(priv,SI5351_CLK0_CTRL + (u8)clk, reg_val);
|
|
|
|
}
|
|
|
|
static void si5351_init(struct si5351_priv *priv)
|
|
{
|
|
si5351_write(priv,SI5351_CRYSTAL_LOAD, SI5351_CRYSTAL_LOAD_10PF);
|
|
return ;
|
|
}
|
|
|
|
static void si5351_set_freq(struct si5351_priv *priv,u32 freq, u32 pll_freq, enum si5351_clock clk)
|
|
{
|
|
struct Si5351RegSet ms_reg;
|
|
struct Si5351RegSet pll_reg;
|
|
enum si5351_pll target_pll;
|
|
|
|
u32 ret;
|
|
|
|
/* Calculate the synth parameters */
|
|
/* If pll_freq is 0, let the algorithm pick a PLL frequency */
|
|
if(pll_freq == 0)
|
|
{
|
|
pll_freq = multisynth_calc(freq, &ms_reg);
|
|
}
|
|
/* TODO: bounds checking */
|
|
else
|
|
{
|
|
multisynth_recalc(freq, pll_freq, &ms_reg);
|
|
}
|
|
/* Determine which PLL to use */
|
|
/* CLK0 gets PLLA, CLK1 gets PLLB */
|
|
/* CLK2 gets PLLB if necessary */
|
|
/* Only good for Si5351A3 variant at the moment */
|
|
if(clk == SI5351_CLK0)
|
|
{
|
|
target_pll = SI5351_PLLA;
|
|
priv->plla_freq = pll_freq;
|
|
}
|
|
else if(clk == SI5351_CLK1)
|
|
{
|
|
target_pll = SI5351_PLLB;
|
|
priv->pllb_freq = pll_freq;
|
|
}
|
|
else
|
|
{
|
|
/* need to account for CLK2 set before CLK1 */
|
|
if(priv->pllb_freq == 0)
|
|
{
|
|
target_pll = SI5351_PLLB;
|
|
priv->pllb_freq = pll_freq;
|
|
}
|
|
else
|
|
{
|
|
target_pll = SI5351_PLLB;
|
|
pll_freq = priv->pllb_freq;
|
|
multisynth_recalc(freq, pll_freq, &ms_reg);
|
|
}
|
|
}
|
|
|
|
ret=pll_calc(pll_freq, &pll_reg, 0);
|
|
/* Derive the register values to write */
|
|
/* Prepare an array for parameters to be written to */
|
|
u8 params[30];
|
|
u8 i = 0;
|
|
u8 temp;
|
|
/* PLL parameters first */
|
|
if(ret== 0)
|
|
{
|
|
/* Registers 26-27 */
|
|
temp = ((pll_reg.p3 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
temp = (u8)(pll_reg.p3 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Register 28 */
|
|
temp = (u8)((pll_reg.p1 >> 16) & 0x03);
|
|
params[i++] = temp;
|
|
|
|
/* Registers 29-30 */
|
|
temp = (u8)((pll_reg.p1 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
temp = (u8)(pll_reg.p1 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Register 31 */
|
|
temp = (u8)((pll_reg.p3 >> 12) & 0xF0);
|
|
temp += (u8)((pll_reg.p2 >> 16) & 0x0F);
|
|
params[i++] = temp;
|
|
|
|
/* Registers 32-33 */
|
|
temp = (u8)((pll_reg.p2 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
temp = (u8)(pll_reg.p2 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Write the parameters */
|
|
if(target_pll == SI5351_PLLA)
|
|
{
|
|
si5351_write_bulk(priv,SI5351_PLLA_PARAMETERS, i + 1, params);
|
|
}
|
|
else if(target_pll == SI5351_PLLB)
|
|
{
|
|
si5351_write_bulk(priv,SI5351_PLLB_PARAMETERS, i + 1, params);
|
|
}
|
|
}
|
|
/* Now the multisynth parameters */
|
|
memset (params, 0, 30);
|
|
i = 0;
|
|
|
|
/* Registers 42-43 */
|
|
temp = (u8)((ms_reg.p3 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
temp = (u8)(ms_reg.p3 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Register 44 */
|
|
/* TODO: add code for output divider */
|
|
temp = (u8)((ms_reg.p1 >> 16) & 0x03);
|
|
params[i++] = temp;
|
|
|
|
/* Registers 45-46 */
|
|
temp = (u8)((ms_reg.p1 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
temp = (u8)(ms_reg.p1 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Register 47 */
|
|
temp = (u8)((ms_reg.p3 >> 12) & 0xF0);
|
|
temp += (u8)((ms_reg.p2 >> 16) & 0x0F);
|
|
params[i++] = temp;
|
|
|
|
/* Registers 48-49 */
|
|
temp = (u8)((ms_reg.p2 >> 8) & 0xFF);
|
|
params[i++] = temp;
|
|
temp = (u8)(ms_reg.p2 & 0xFF);
|
|
params[i++] = temp;
|
|
|
|
/* Write the parameters */
|
|
switch(clk)
|
|
{
|
|
case SI5351_CLK0:
|
|
si5351_write_bulk(priv,SI5351_CLK0_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK1:
|
|
si5351_write_bulk(priv,SI5351_CLK1_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK2:
|
|
si5351_write_bulk(priv,SI5351_CLK2_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK3:
|
|
si5351_write_bulk(priv,SI5351_CLK3_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK4:
|
|
si5351_write_bulk(priv,SI5351_CLK4_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK5:
|
|
si5351_write_bulk(priv,SI5351_CLK5_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK6:
|
|
si5351_write_bulk(priv,SI5351_CLK6_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
case SI5351_CLK7:
|
|
si5351_write_bulk(priv,SI5351_CLK7_PARAMETERS, i + 1, params);
|
|
si5351_set_ms_source(priv,clk, target_pll);
|
|
break;
|
|
}
|
|
|
|
}
|
|
//end
|
|
static int rs6060_set_reg(struct m88rs6060_dev *dev, u8 reg, u8 data)
|
|
{
|
|
|
|
u8 buf[] = { reg, data };
|
|
u8 val;
|
|
int ret;
|
|
struct i2c_msg msg = {
|
|
.addr = dev->config.tuner_adr,.flags = 0,.buf = buf,.len = 2
|
|
};
|
|
|
|
val = 0x11;
|
|
ret = regmap_write(dev->regmap, 0x03, val);
|
|
if (ret)
|
|
dev_dbg(&dev->base->i2c->dev, "fail=%d\n", ret);
|
|
|
|
ret = i2c_transfer(dev->base->i2c, &msg, 1);
|
|
if (ret != 1) {
|
|
dev_err(&dev->base->i2c->dev,
|
|
"0x%02x (ret=%i, reg=0x%02x, value=0x%02x)\n",
|
|
dev->config.tuner_adr, ret, reg, data);
|
|
return -EREMOTEIO;
|
|
}
|
|
|
|
dev_dbg(&dev->base->i2c->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
|
|
dev->config.tuner_adr, reg, data);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rs6060_get_reg(struct m88rs6060_dev *dev, u8 reg)
|
|
{
|
|
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret;
|
|
unsigned val;
|
|
u8 b0[] = { reg };
|
|
u8 b1[] = { 0 };
|
|
struct i2c_msg msg[] = {
|
|
{
|
|
.addr = dev->config.tuner_adr,
|
|
.flags = 0,
|
|
.buf = b0,
|
|
.len = 1},
|
|
{
|
|
.addr = dev->config.tuner_adr,
|
|
.flags = I2C_M_RD,
|
|
.buf = b1,
|
|
.len = 1}
|
|
};
|
|
|
|
val = dev->config.repeater_value;
|
|
ret = regmap_write(dev->regmap, 0x03, val);
|
|
if (ret)
|
|
dev_dbg(&i2c->dev, "fail=%d\n", ret);
|
|
|
|
ret = i2c_transfer(i2c, msg, 2);
|
|
if (ret != 2) {
|
|
dev_err(&i2c->dev, "0x%02x (ret=%d, reg=0x%02x)\n",
|
|
dev->config.tuner_adr, ret, reg);
|
|
return -EREMOTEIO;
|
|
}
|
|
|
|
dev_dbg(&i2c->dev, "0x%02x reg 0x%02x, value 0x%02x\n",
|
|
dev->config.tuner_adr, reg, b1[0]);
|
|
|
|
return b1[0];
|
|
|
|
}
|
|
|
|
static int m88rs6060_fireware_download(struct m88rs6060_dev *dev, u8 reg,
|
|
const u8 * data, int len)
|
|
{
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret;
|
|
u8 buf[70];
|
|
struct i2c_msg msg = {
|
|
.addr = dev->config.demod_adr,.flags = 0,.buf = buf,.len =
|
|
len + 1
|
|
};
|
|
|
|
buf[0] = reg;
|
|
memcpy(&buf[1], data, len);
|
|
|
|
ret = i2c_transfer(i2c, &msg, 1);
|
|
if (ret != 1) {
|
|
dev_err(&i2c->dev,
|
|
"0x%02x (ret=%i, reg=0x%02x)\n",
|
|
dev->config.tuner_adr, ret, reg);
|
|
return -EREMOTEIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int m88rs6060_update_bits(struct m88rs6060_dev *dev,
|
|
u8 reg, u8 mask, u8 val)
|
|
{
|
|
int ret;
|
|
unsigned tmp;
|
|
|
|
/* no need for read if whole reg is written */
|
|
if (mask != 0xff) {
|
|
ret = regmap_read(dev->regmap, reg, &tmp);
|
|
if (ret)
|
|
return ret;
|
|
|
|
val &= mask;
|
|
tmp &= ~mask;
|
|
val |= tmp;
|
|
}
|
|
|
|
return regmap_write(dev->regmap, reg, val);
|
|
}
|
|
|
|
static void m88rs6060_calc_PLS_gold_code(u8 * pNormalCode, u32 PLSGoldCode)
|
|
{
|
|
struct PLS_Table_t {
|
|
u32 iIndex;
|
|
u8 PLSCode[3];
|
|
};
|
|
|
|
struct PLS_Table_t PLS_List[] = {
|
|
{0, {0x01, 0x00, 0x00}},
|
|
{5000, {0x0d, 0xe0, 0x00}},
|
|
{10000, {0x51, 0x15, 0x00}},
|
|
{15000, {0xcf, 0xc9, 0x00}},
|
|
{20000, {0x67, 0x33, 0x03}},
|
|
{25000, {0x02, 0xc9, 0x02}},
|
|
{30000, {0xe5, 0xc6, 0x01}},
|
|
{35000, {0xdb, 0xc0, 0x03}},
|
|
{40000, {0x7c, 0x5f, 0x02}},
|
|
{45000, {0x8d, 0x65, 0x00}},
|
|
{50000, {0x14, 0x96, 0x00}},
|
|
{55000, {0xf7, 0x61, 0x03}},
|
|
{60000, {0xbc, 0x28, 0x00}},
|
|
{65000, {0x77, 0xa9, 0x01}},
|
|
{70000, {0xe7, 0x05, 0x01}},
|
|
{75000, {0x88, 0x85, 0x01}},
|
|
{80000, {0x2f, 0xbb, 0x02}},
|
|
{85000, {0xe1, 0x07, 0x00}},
|
|
{90000, {0xd5, 0x67, 0x01}},
|
|
{95000, {0x94, 0x37, 0x03}},
|
|
{100000, {0x57, 0x39, 0x02}},
|
|
{105000, {0xc7, 0x03, 0x00}},
|
|
{110000, {0xbf, 0x12, 0x00}},
|
|
{115000, {0x50, 0x0e, 0x00}},
|
|
{120000, {0xca, 0xc4, 0x00}},
|
|
{125000, {0x46, 0xc3, 0x00}},
|
|
{130000, {0x2f, 0xc6, 0x01}},
|
|
{135000, {0x7c, 0xe5, 0x01}},
|
|
{140000, {0xb9, 0x36, 0x01}},
|
|
{145000, {0x9d, 0xe5, 0x01}},
|
|
{150000, {0xc4, 0x32, 0x01}},
|
|
{155000, {0x13, 0xb3, 0x00}},
|
|
{160000, {0x0c, 0x9f, 0x02}},
|
|
{165000, {0xb2, 0xb5, 0x03}},
|
|
{170000, {0xac, 0x7e, 0x01}},
|
|
{175000, {0xb6, 0xa2, 0x01}},
|
|
{180000, {0xb6, 0x3e, 0x01}},
|
|
{185000, {0x17, 0x2c, 0x02}},
|
|
{190000, {0xd7, 0x2a, 0x02}},
|
|
{195000, {0x93, 0x61, 0x02}},
|
|
{200000, {0x67, 0x92, 0x02}},
|
|
{205000, {0x38, 0x07, 0x01}},
|
|
{210000, {0xb4, 0x5a, 0x01}},
|
|
{215000, {0xed, 0x31, 0x02}},
|
|
{220000, {0x9e, 0x4d, 0x02}},
|
|
{225000, {0x17, 0x08, 0x02}},
|
|
{230000, {0x37, 0xb9, 0x00}},
|
|
{235000, {0x2c, 0xed, 0x00}},
|
|
{240000, {0xe0, 0x64, 0x00}},
|
|
{245000, {0x90, 0x39, 0x01}},
|
|
{250000, {0x35, 0x0e, 0x01}},
|
|
{255000, {0x1c, 0x9e, 0x02}},
|
|
{260000, {0x58, 0x78, 0x00}}
|
|
};
|
|
|
|
u8 x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15,
|
|
x16, x17;
|
|
int i;
|
|
u8 tmp;
|
|
|
|
u32 ulPLSCode = 0, ulPLSIndex = 0;
|
|
|
|
int iPLSCnt =
|
|
sizeof(PLS_List) / sizeof(struct PLS_Table_t), iPLSListIndex;
|
|
u8 iPLSCode[3];
|
|
|
|
ulPLSCode = PLSGoldCode;
|
|
iPLSListIndex = ulPLSCode / 5000;
|
|
|
|
if (iPLSListIndex > iPLSCnt - 1)
|
|
iPLSListIndex = iPLSCnt - 1;
|
|
|
|
ulPLSIndex = PLS_List[iPLSListIndex].iIndex;
|
|
iPLSCode[0] = PLS_List[iPLSListIndex].PLSCode[0];
|
|
iPLSCode[1] = PLS_List[iPLSListIndex].PLSCode[1];
|
|
iPLSCode[2] = PLS_List[iPLSListIndex].PLSCode[2];
|
|
|
|
x0 = (iPLSCode[0] >> 0) & 0x01;
|
|
x1 = (iPLSCode[0] >> 1) & 0x01;
|
|
x2 = (iPLSCode[0] >> 2) & 0x01;
|
|
x3 = (iPLSCode[0] >> 3) & 0x01;
|
|
x4 = (iPLSCode[0] >> 4) & 0x01;
|
|
x5 = (iPLSCode[0] >> 5) & 0x01;
|
|
x6 = (iPLSCode[0] >> 6) & 0x01;
|
|
x7 = (iPLSCode[0] >> 7) & 0x01;
|
|
x8 = (iPLSCode[1] >> 0) & 0x01;
|
|
x9 = (iPLSCode[1] >> 1) & 0x01;
|
|
x10 = (iPLSCode[1] >> 2) & 0x01;
|
|
x11 = (iPLSCode[1] >> 3) & 0x01;
|
|
x12 = (iPLSCode[1] >> 4) & 0x01;
|
|
x13 = (iPLSCode[1] >> 5) & 0x01;
|
|
x14 = (iPLSCode[1] >> 6) & 0x01;
|
|
x15 = (iPLSCode[1] >> 7) & 0x01;
|
|
x16 = (iPLSCode[2] >> 0) & 0x01;
|
|
x17 = (iPLSCode[2] >> 1) & 0x01;
|
|
|
|
for (i = ulPLSIndex; i <= ulPLSCode; i++) {
|
|
iPLSCode[0] =
|
|
(x7 << 7) + (x6 << 6) + (x5 << 5) + (x4 << 4) + (x3 << 3) +
|
|
(x2 << 2) + (x1 << 1) + (x0 << 0);
|
|
iPLSCode[1] =
|
|
(x15 << 7) + (x14 << 6) + (x13 << 5) + (x12 << 4) +
|
|
(x11 << 3) + (x10 << 2) + (x9 << 1) + (x8 << 0);
|
|
iPLSCode[2] = (x17 << 1) + x16;
|
|
|
|
tmp = (x0 ^ x7) & 0x01;
|
|
x0 = x1;
|
|
x1 = x2;
|
|
x2 = x3;
|
|
x3 = x4;
|
|
x4 = x5;
|
|
x5 = x6;
|
|
x6 = x7;
|
|
x7 = x8;
|
|
x8 = x9;
|
|
x9 = x10;
|
|
x10 = x11;
|
|
x11 = x12;
|
|
x12 = x13;
|
|
x13 = x14;
|
|
x14 = x15;
|
|
x15 = x16;
|
|
x16 = x17;
|
|
x17 = tmp;
|
|
|
|
}
|
|
|
|
pNormalCode[0] = iPLSCode[0];
|
|
pNormalCode[1] = iPLSCode[1];
|
|
pNormalCode[2] = iPLSCode[2];
|
|
|
|
return;
|
|
}
|
|
|
|
static int m88rs6060_get_gain(struct m88rs6060_dev *dev, u32 freq_MHz,
|
|
s32 * p_gain)
|
|
{
|
|
static s32 bb_list_dBm[16][16] = {
|
|
{-5000, -4999, -4397, -4044, -3795, -3601, -3442, -3309, -3193,
|
|
-3090, -2999, -2916, -2840, -2771, -2706, -2647},
|
|
{-2590, -2538, -2488, -2441, -2397, -2354, -2314, -2275, -2238,
|
|
-2203, -2169, -2136, -2104, -2074, -2044, -2016},
|
|
{-1988, -1962, -1936, -1911, -1886, -1862, -1839, -1817, -1795,
|
|
-1773, -1752, -1732, -1712, -1692, -1673, -1655},
|
|
{-1636, -1618, -1601, -1584, -1567, -1550, -1534, -1518, -1502,
|
|
-1487, -1472, -1457, -1442, -1428, -1414, -1400},
|
|
{-1386, -1373, -1360, -1347, -1334, -1321, -1309, -1296, -1284,
|
|
-1272, -1260, -1249, -1237, -1226, -1215, -1203},
|
|
{-1193, -1182, -1171, -1161, -1150, -1140, -1130, -1120, -1110,
|
|
-1100, -1090, -1081, -1071, -1062, -1052, -1043},
|
|
{-1034, -1025, -1016, -1007, -999, -990, -982, -973, -965, -956,
|
|
-948, -940, -932, -924, -916, -908},
|
|
{-900, -893, -885, -877, -870, -862, -855, -848, -840, -833,
|
|
-826, -819, -812, -805, -798, -791},
|
|
{-784, -778, -771, -764, -758, -751, -745, -738, -732, -725,
|
|
-719, -713, -706, -700, -694, -688},
|
|
{-682, -676, -670, -664, -658, -652, -647, -641, -635, -629,
|
|
-624, -618, -612, -607, -601, -596},
|
|
{-590, -585, -580, -574, -569, -564, -558, -553, -548, -543,
|
|
-538, -533, -528, -523, -518, -513},
|
|
{-508, -503, -498, -493, -488, -483, -479, -474, -469, -464,
|
|
-460, -455, -450, -446, -441, -437},
|
|
{-432, -428, -423, -419, -414, -410, -405, -401, -397, -392,
|
|
-388, -384, -379, -375, -371, -367},
|
|
{-363, -358, -354, -350, -346, -342, -338, -334, -330, -326,
|
|
-322, -318, -314, -310, -306, -302},
|
|
{-298, -294, -290, -287, -283, -279, -275, -271, -268, -264,
|
|
-260, -257, -253, -249, -246, -242},
|
|
{-238, -235, -231, -227, -224, -220, -217, -213, -210, -206,
|
|
-203, -199, -196, -192, -189, -186}
|
|
|
|
};
|
|
|
|
s32 BB_Power = 0;
|
|
u32 Total_Gain = 8000;
|
|
s32 delta = 0;
|
|
|
|
u8 reg5a, reg5f, reg77, reg76, reg3f;
|
|
u8 reg96 = 0;
|
|
|
|
u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290;
|
|
u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300, PGA2_GC = 300, TIA_GC =
|
|
300;
|
|
u32 PGA2_cri = 0, PGA2_crf = 0;
|
|
u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0;
|
|
|
|
u32 i = 0;
|
|
|
|
u32 RFGS[13] =
|
|
{ 0, 276, 278, 283, 272, 294, 296, 292, 292, 299, 305, 292, 300 };
|
|
u32 IFGS[12] =
|
|
{ 0, 0, 232, 268, 266, 289, 295, 290, 291, 298, 304, 304 };
|
|
u32 BBGS[13] =
|
|
{ 0, 296, 297, 295, 298, 302, 293, 292, 286, 294, 278, 298, 267 };
|
|
|
|
reg5a = rs6060_get_reg(dev, 0x5A);
|
|
RF_GC = reg5a & 0x0f;
|
|
|
|
reg5f = rs6060_get_reg(dev, 0x5F);
|
|
IF_GC = reg5f & 0x0f;
|
|
|
|
reg3f = rs6060_get_reg(dev, 0x3F);
|
|
TIA_GC = (reg3f >> 4) & 0x07;
|
|
|
|
reg77 = rs6060_get_reg(dev, 0x77);
|
|
BB_GC = (reg77 >> 4) & 0x0f;
|
|
|
|
reg76 = rs6060_get_reg(dev, 0x76);
|
|
PGA2_GC = reg76 & 0x3f;
|
|
PGA2_cri = PGA2_GC >> 2;
|
|
PGA2_crf = PGA2_GC & 0x03;
|
|
|
|
if (freq_MHz >= 1750) {
|
|
RFGS[1] = 240;
|
|
RFGS[2] = 260;
|
|
IFGS[2] = 200;
|
|
IFGS[3] = 245;
|
|
IFGS[4] = 255;
|
|
} else if (freq_MHz >= 1350) {
|
|
RFGS[12] = 285;
|
|
} else {
|
|
RFGS[1] = 310;
|
|
RFGS[2] = 293;
|
|
IFGS[2] = 270;
|
|
IFGS[3] = 290;
|
|
IFGS[4] = 280;
|
|
IFGS[11] = 320;
|
|
}
|
|
|
|
for (i = 0; i <= RF_GC; i++) {
|
|
RFG += RFGS[i];
|
|
}
|
|
|
|
for (i = 1; i <= IF_GC; i++) {
|
|
IFG += IFGS[i];
|
|
}
|
|
|
|
TIAG = TIA_GC * TIA_GS;
|
|
|
|
for (i = 0; i <= BB_GC; i++) {
|
|
BBG += BBGS[i];
|
|
}
|
|
|
|
PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
|
|
Total_Gain = RFG + IFG - TIAG + BBG + PGA2G;
|
|
|
|
if (freq_MHz >= 1750) {
|
|
delta = 800;
|
|
} else if (freq_MHz >= 1350) {
|
|
delta = 900;
|
|
} else {
|
|
delta = 1000;
|
|
}
|
|
|
|
reg96 = rs6060_get_reg(dev, 0x96);
|
|
BB_Power = bb_list_dBm[(reg96 >> 4) & 0x0f][reg96 & 0x0f];
|
|
*p_gain = Total_Gain - delta - BB_Power;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static void rs6060_wakeup(struct m88rs6060_dev *dev)
|
|
{
|
|
rs6060_set_reg(dev, 0x10, 0xfb);
|
|
rs6060_set_reg(dev, 0x11, 0x1);
|
|
rs6060_set_reg(dev, 0x7, 0x7d);
|
|
msleep(10);
|
|
|
|
return;
|
|
}
|
|
|
|
static void m88rs6060_hard_rest(struct m88rs6060_dev *dev)
|
|
{
|
|
unsigned val;
|
|
|
|
rs6060_set_reg(dev, 0x04, 0x01);
|
|
rs6060_set_reg(dev, 0x04, 0x00);
|
|
|
|
regmap_read(dev->regmap, 0x04, &val);
|
|
val&=~0x01;
|
|
regmap_write(dev->regmap, 0x04,val);
|
|
|
|
msleep(1);
|
|
rs6060_wakeup(dev);
|
|
|
|
|
|
regmap_read(dev->regmap, 0x08, &val);
|
|
regmap_write(dev->regmap, 0x08, (val | 0x01));
|
|
|
|
regmap_read(dev->regmap, 0x0b, &val);
|
|
regmap_write(dev->regmap, 0x0b, (val | 0x1));
|
|
|
|
regmap_read(dev->regmap, 0xb2, &val);
|
|
if (val == 0x1) {
|
|
regmap_write(dev->regmap, 0x00, 0x00);
|
|
regmap_write(dev->regmap, 0xb2, 0x00);
|
|
}
|
|
|
|
regmap_write(dev->regmap, 0x07, 0x80);
|
|
regmap_write(dev->regmap, 0x07, 0x00);
|
|
msleep(1);
|
|
regmap_read(dev->regmap, 0x08, &val);
|
|
regmap_write(dev->regmap, 0x8, (val | 0x1));
|
|
|
|
return;
|
|
}
|
|
|
|
static void rs6060_select_mclk(struct m88rs6060_dev *dev, u32 freq_MHz,
|
|
u32 symbol_rate)
|
|
{
|
|
u32 adc_freq_MHz[3] = { 96, 93, 99 };
|
|
u8 reg16_list[3] = { 96, 92, 100 }, reg15, reg16;
|
|
u32 offset_MHz[3];
|
|
u32 max_offset = 0;
|
|
int i = 0;
|
|
reg16 = 96;
|
|
dev->mclk = 96000;
|
|
if (symbol_rate >= 46000) {
|
|
dev->mclk = 99000;
|
|
reg16 = 100;
|
|
} else {
|
|
for (i = 0; i < 3; i++) {
|
|
offset_MHz[i] = freq_MHz % adc_freq_MHz[i];
|
|
|
|
if (offset_MHz[i] > (adc_freq_MHz[i] / 2))
|
|
offset_MHz[i] = adc_freq_MHz[i] - offset_MHz[i];
|
|
|
|
if (offset_MHz[i] > max_offset) {
|
|
|
|
max_offset = offset_MHz[i];
|
|
reg16 = reg16_list[i];
|
|
dev->mclk = adc_freq_MHz[i] * 1000;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
reg15 = rs6060_get_reg(dev, 0x15);
|
|
reg15 &= ~0x1;
|
|
rs6060_set_reg(dev, 0x15, reg15);
|
|
rs6060_set_reg(dev, 0x16, reg16);
|
|
rs6060_set_reg(dev, 0x17, 0xc1);
|
|
rs6060_set_reg(dev, 0x17, 0x81);
|
|
|
|
msleep(5);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static void rs6060_set_ts_mclk(struct m88rs6060_dev *dev, u32 mclk)
|
|
{
|
|
u8 reg15, reg16, reg1D, reg1E, reg1F, tmp;
|
|
u8 sm, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
|
|
u16 pll_div_fb, N;
|
|
u32 div;
|
|
|
|
reg15 = rs6060_get_reg(dev, 0x15);
|
|
reg16 = rs6060_get_reg(dev, 0x16);
|
|
reg1D = rs6060_get_reg(dev, 0x1d);
|
|
|
|
if (dev->config.ts_mode != MtFeTsOutMode_Serial) {
|
|
if (reg16 == 92) {
|
|
tmp = 93;
|
|
} else if (reg16 == 100) {
|
|
tmp = 99;
|
|
} else // if(reg16 == 96)
|
|
{
|
|
tmp = 96;
|
|
}
|
|
|
|
mclk *= tmp;
|
|
mclk /= 96;
|
|
}
|
|
|
|
pll_div_fb = (reg15 & 0x01) << 8;
|
|
pll_div_fb += reg16;
|
|
pll_div_fb += 32;
|
|
|
|
div = 9000 * pll_div_fb * 4;
|
|
div /= mclk;
|
|
|
|
if (dev->config.ts_mode == MtFeTsOutMode_Serial) {
|
|
if (div <= 32) {
|
|
N = 2;
|
|
|
|
f0 = 0;
|
|
f1 = div / N;
|
|
f2 = div - f1;
|
|
f3 = 0;
|
|
} else if (div <= 64) {
|
|
N = 4;
|
|
|
|
f0 = div / N;
|
|
f1 = (div - f0) / (N - 1);
|
|
f2 = (div - f0 - f1) / (N - 2);
|
|
f3 = div - f0 - f1 - f2;
|
|
} else {
|
|
N = 4;
|
|
|
|
f0 = 16;
|
|
f1 = 16;
|
|
f2 = 16;
|
|
f3 = 16;
|
|
}
|
|
|
|
if (f0 == 16)
|
|
f0 = 0;
|
|
else if ((f0 < 8) && (f0 != 0))
|
|
f0 = 8;
|
|
|
|
if (f1 == 16)
|
|
f1 = 0;
|
|
else if ((f1 < 8) && (f1 != 0))
|
|
f1 = 8;
|
|
|
|
if (f2 == 16)
|
|
f2 = 0;
|
|
else if ((f2 < 8) && (f2 != 0))
|
|
f2 = 8;
|
|
|
|
if (f3 == 16)
|
|
f3 = 0;
|
|
else if ((f3 < 8) && (f3 != 0))
|
|
f3 = 8;
|
|
} else {
|
|
if (div <= 32) {
|
|
N = 2;
|
|
|
|
f0 = 0;
|
|
f1 = div / N;
|
|
f2 = div - f1;
|
|
f3 = 0;
|
|
} else if (div <= 48) {
|
|
N = 3;
|
|
|
|
f0 = div / N;
|
|
f1 = (div - f0) / (N - 1);
|
|
f2 = div - f0 - f1;
|
|
f3 = 0;
|
|
} else if (div <= 64) {
|
|
N = 4;
|
|
|
|
f0 = div / N;
|
|
f1 = (div - f0) / (N - 1);
|
|
f2 = (div - f0 - f1) / (N - 2);
|
|
f3 = div - f0 - f1 - f2;
|
|
} else {
|
|
N = 4;
|
|
|
|
f0 = 16;
|
|
f1 = 16;
|
|
f2 = 16;
|
|
f3 = 16;
|
|
}
|
|
|
|
if (f0 == 16)
|
|
f0 = 0;
|
|
else if ((f0 < 9) && (f0 != 0))
|
|
f0 = 9;
|
|
|
|
if (f1 == 16)
|
|
f1 = 0;
|
|
else if ((f1 < 9) && (f1 != 0))
|
|
f1 = 9;
|
|
|
|
if (f2 == 16)
|
|
f2 = 0;
|
|
else if ((f2 < 9) && (f2 != 0))
|
|
f2 = 9;
|
|
|
|
if (f3 == 16)
|
|
f3 = 0;
|
|
else if ((f3 < 9) && (f3 != 0))
|
|
f3 = 9;
|
|
}
|
|
|
|
sm = N - 1;
|
|
|
|
reg1D &= ~0x03;
|
|
reg1D |= sm;
|
|
reg1D |= 0x80;
|
|
|
|
reg1E = ((f3 << 4) + f2) & 0xFF;
|
|
reg1F = ((f1 << 4) + f0) & 0xFF;
|
|
|
|
rs6060_set_reg(dev, 0x1d, reg1D);
|
|
rs6060_set_reg(dev, 0x1e, reg1E);
|
|
rs6060_set_reg(dev, 0x1f, reg1F);
|
|
msleep(1);
|
|
|
|
}
|
|
static int rs6060_get_ts_mclk(struct m88rs6060_dev *dev,u32*mclk )
|
|
{
|
|
u8 reg15, reg16, reg1D, reg1E, reg1F;
|
|
u8 sm, f0, f1, f2, f3;
|
|
u16 pll_div_fb, N;
|
|
u32 MCLK_KHz;
|
|
|
|
|
|
*mclk = MT_FE_MCLK_KHZ;
|
|
|
|
reg15 = rs6060_get_reg(dev, 0x15);
|
|
reg16 = rs6060_get_reg(dev, 0x16);
|
|
reg1D = rs6060_get_reg(dev, 0x1d);
|
|
reg1E = rs6060_get_reg(dev, 0x1e);
|
|
reg1F = rs6060_get_reg(dev, 0x1f);
|
|
|
|
MCLK_KHz = 9000;
|
|
pll_div_fb = reg15 & 0x01;
|
|
pll_div_fb <<= 8;
|
|
pll_div_fb += reg16;
|
|
|
|
MCLK_KHz *= (pll_div_fb + 32);
|
|
|
|
sm = reg1D & 0x03;
|
|
|
|
f3 = (reg1E >> 4) & 0x0F;
|
|
f2 = reg1E & 0x0F;
|
|
f1 = (reg1F >> 4) & 0x0F;
|
|
f0 = reg1F & 0x0F;
|
|
|
|
if(f3 == 0) f3 = 16;
|
|
if(f2 == 0) f2 = 16;
|
|
if(f1 == 0) f1 = 16;
|
|
if(f0 == 0) f0 = 16;
|
|
N = f2 + f1;
|
|
|
|
switch(sm){
|
|
case 3:
|
|
N = f3 + f2 + f1 + f0;
|
|
break;
|
|
case 2:
|
|
N = f2 + f1 + f0;
|
|
break;
|
|
case 1:
|
|
case 0:
|
|
default:
|
|
N = f2 + f1;
|
|
break;
|
|
}
|
|
|
|
MCLK_KHz *= 4;
|
|
MCLK_KHz /= N;
|
|
|
|
*mclk = MCLK_KHz;
|
|
|
|
return 0;
|
|
|
|
}
|
|
static int rs6060_set_pll_freq(struct m88rs6060_dev *dev, u32 tuner_freq_MHz)
|
|
{
|
|
u32 fcry_KHz, ulNDiv1, ulNDiv2;
|
|
u8 refDiv1, refDiv2, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, div1m,
|
|
div1p5m, lodiv_en_opt_div2;
|
|
u8 reg27, reg29;
|
|
u8 tmp;
|
|
|
|
fcry_KHz = dev->config.clk / 1000; /*tuner crycle */
|
|
if (fcry_KHz == 27000) {
|
|
|
|
div1m = 19;
|
|
div1p5m = 10;
|
|
rs6060_set_reg(dev, 0x41, 0x82);
|
|
} else if (fcry_KHz == 24000) {
|
|
div1m = 16;
|
|
div1p5m = 8;
|
|
rs6060_set_reg(dev, 0x41, 0x8a);
|
|
|
|
} else {
|
|
|
|
div1m = 19;
|
|
div1p5m = 10;
|
|
rs6060_set_reg(dev, 0x41, 0x82);
|
|
|
|
}
|
|
if (tuner_freq_MHz >= 1550) {
|
|
ucLoDiv1 = 2;
|
|
ucLomod1 = 0;
|
|
refDiv1 = div1m;
|
|
ucLoDiv2 = 2;
|
|
ucLomod2 = 0;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 1380) {
|
|
ucLoDiv1 = 3;
|
|
ucLomod1 = 16;
|
|
refDiv1 = div1p5m;
|
|
ucLoDiv2 = 2;
|
|
ucLomod2 = 0;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 1070) {
|
|
ucLoDiv1 = 3;
|
|
ucLomod1 = 16;
|
|
refDiv1 = div1p5m;
|
|
ucLoDiv2 = 3;
|
|
ucLomod2 = 16;
|
|
refDiv2 = div1p5m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 1000) {
|
|
ucLoDiv1 = 4;
|
|
ucLomod1 = 64;
|
|
refDiv1 = div1m;
|
|
ucLoDiv2 = 4;
|
|
ucLomod2 = 64;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 775) {
|
|
ucLoDiv1 = 4;
|
|
ucLomod1 = 64;
|
|
refDiv1 = div1m;
|
|
ucLoDiv2 = 4;
|
|
ucLomod2 = 64;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 700) {
|
|
ucLoDiv1 = 6;
|
|
ucLomod1 = 48;
|
|
refDiv1 = div1p5m;
|
|
ucLoDiv2 = 4;
|
|
ucLomod2 = 64;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 520) {
|
|
ucLoDiv1 = 6;
|
|
ucLomod1 = 48;
|
|
refDiv1 = div1p5m;
|
|
ucLoDiv2 = 6;
|
|
ucLomod2 = 48;
|
|
refDiv2 = div1p5m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else if (tuner_freq_MHz >= 375) {
|
|
ucLoDiv1 = 8;
|
|
ucLomod1 = 96;
|
|
refDiv1 = div1m;
|
|
ucLoDiv2 = 8;
|
|
ucLomod2 = 96;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 0;
|
|
} else {
|
|
ucLoDiv1 = 12;
|
|
ucLomod1 = 80;
|
|
refDiv1 = div1m;
|
|
ucLoDiv2 = 12;
|
|
ucLomod2 = 80;
|
|
refDiv2 = div1m;
|
|
lodiv_en_opt_div2 = 1;
|
|
}
|
|
|
|
ulNDiv1 =
|
|
((tuner_freq_MHz * 1000 * ucLoDiv1) * (refDiv1 + 8) / fcry_KHz -
|
|
1024) / 2;
|
|
ulNDiv2 =
|
|
((tuner_freq_MHz * 1000 * ucLoDiv2) * (refDiv2 + 8) / fcry_KHz -
|
|
1024) / 2;
|
|
|
|
reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F;
|
|
|
|
rs6060_set_reg(dev, 0x27, reg27);
|
|
rs6060_set_reg(dev, 0x28, (u8) (ulNDiv1 & 0xFF));
|
|
|
|
reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f;
|
|
|
|
rs6060_set_reg(dev, 0x29, reg29);
|
|
rs6060_set_reg(dev, 0x2a, (u8) (ulNDiv2 & 0xFF));
|
|
|
|
refDiv1 = refDiv1 & 0x1F;
|
|
rs6060_set_reg(dev, 0x36, refDiv1);
|
|
|
|
rs6060_set_reg(dev, 0x39, refDiv2);
|
|
|
|
tmp = rs6060_get_reg(dev, 0x3d);
|
|
if (lodiv_en_opt_div2 == 1)
|
|
tmp |= 0x80;
|
|
else
|
|
tmp &= 0x7F;
|
|
|
|
rs6060_set_reg(dev, 0x3d, tmp);
|
|
|
|
if (refDiv1 == 19) {
|
|
rs6060_set_reg(dev, 0x2c, 0x02);
|
|
} else {
|
|
rs6060_set_reg(dev, 0x2c, 0x00);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int rs6060_set_bb(struct m88rs6060_dev *dev,
|
|
u32 symbol_rate_KSs, s32 lpf_offset_KHz)
|
|
{
|
|
u32 f3dB;
|
|
u8 reg40;
|
|
|
|
f3dB = symbol_rate_KSs * 9 / 14 + 2000;
|
|
f3dB += lpf_offset_KHz;
|
|
f3dB = clamp_val(f3dB, 6000U, 43000U);
|
|
reg40 = f3dB / 1000;
|
|
|
|
return rs6060_set_reg(dev, 0x40, reg40);
|
|
|
|
}
|
|
|
|
static void rs6060_init(struct m88rs6060_dev *dev)
|
|
{
|
|
rs6060_set_reg(dev, 0x15, 0x6c);
|
|
rs6060_set_reg(dev, 0x2b, 0x1e);
|
|
|
|
rs6060_wakeup(dev);
|
|
|
|
rs6060_set_reg(dev, 0x24, 0x4);
|
|
rs6060_set_reg(dev, 0x6e, 0x39);
|
|
rs6060_set_reg(dev, 0x83, 0x1);
|
|
|
|
rs6060_set_reg(dev, 0x70, 0x90);
|
|
rs6060_set_reg(dev, 0x71, 0xF0);
|
|
rs6060_set_reg(dev, 0x72, 0xB6);
|
|
rs6060_set_reg(dev, 0x73, 0xEB);
|
|
rs6060_set_reg(dev, 0x74, 0x6F);
|
|
rs6060_set_reg(dev, 0x75, 0xFC);
|
|
|
|
return;
|
|
}
|
|
|
|
static void m88res6060_set_ts_mode(struct m88rs6060_dev *dev)
|
|
{
|
|
unsigned tmp, val = 0;
|
|
regmap_read(dev->regmap, 0x0b, &val);
|
|
val &= ~0x1;
|
|
regmap_write(dev->regmap, 0x0b, val);
|
|
|
|
regmap_read(dev->regmap, 0xfd, &tmp);
|
|
if (dev->config.ts_mode == MtFeTsOutMode_Parallel) {
|
|
tmp &= ~0x01;
|
|
tmp &= ~0x04;
|
|
|
|
regmap_write(dev->regmap, 0xfa, 0x01);
|
|
regmap_write(dev->regmap, 0xf1, 0x60);
|
|
regmap_write(dev->regmap, 0xfa, 0x00);
|
|
} else if (dev->config.ts_mode == MtFeTsOutMode_Serial) {
|
|
|
|
tmp &= ~0x01;
|
|
tmp |= 0x04;
|
|
} else {
|
|
tmp |= 0x01;
|
|
tmp &= ~0x04;
|
|
|
|
regmap_write(dev->regmap, 0xfa, 0x01);
|
|
regmap_write(dev->regmap, 0xf1, 0x60);
|
|
regmap_write(dev->regmap, 0xfa, 0x00);
|
|
}
|
|
|
|
tmp &= ~0xb8;
|
|
tmp |= 0x42;
|
|
tmp |= 0x80;
|
|
regmap_write(dev->regmap, 0xfd, tmp);
|
|
|
|
val = 0;
|
|
if (dev->config.ts_mode != MtFeTsOutMode_Serial) {
|
|
tmp = MT_FE_ENHANCE_TS_PIN_LEVEL_PARALLEL_CI;
|
|
|
|
val |= tmp & 0x03;
|
|
val |= (tmp << 2) & 0x0c;
|
|
val |= (tmp << 4) & 0x30;
|
|
val |= (tmp << 6) & 0xc0;
|
|
} else {
|
|
val = 0x00;
|
|
}
|
|
|
|
regmap_write(dev->regmap, 0x0a, val);
|
|
|
|
regmap_read(dev->regmap, 0x0b, &tmp);
|
|
if (dev->config.ts_pinswitch) {
|
|
tmp |= 0x20;
|
|
} else {
|
|
tmp &= ~0x20;
|
|
}
|
|
tmp |= 0x1;
|
|
regmap_write(dev->regmap, 0x0b, tmp);
|
|
regmap_read(dev->regmap, 0x0c, &tmp);
|
|
regmap_write(dev->regmap, 0xf4, 0x01);
|
|
tmp &= ~0x80;
|
|
regmap_write(dev->regmap, 0x0c, tmp);
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
static int m88rs6060_set_frontend(struct dvb_frontend *fe)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
int ret;
|
|
u32 symbol_rate_KSs;
|
|
unsigned tmp, tmp1;
|
|
static const struct reg_sequence reset_buf[] = {
|
|
{0x7, 0x80}, {0x7, 0x0}
|
|
|
|
};
|
|
u32 realFreq;
|
|
s16 lpf_offset_KHz = 0;
|
|
u32 target_mclk = 144000;
|
|
u32 u32tmp;
|
|
s32 s32tmp;
|
|
u32 pls_mode, pls_code;
|
|
u8 pls[] = { 0x1, 0, 0 }, isi;
|
|
u8 buf[2];
|
|
int i = 0, j = 0;
|
|
unsigned tsid[16];
|
|
bool mis = false;
|
|
|
|
dev_dbg(&i2c->dev,
|
|
"delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u stream_id=%d\n",
|
|
c->delivery_system, c->modulation, c->frequency,
|
|
c->bandwidth_hz, c->symbol_rate, c->inversion, c->stream_id);
|
|
|
|
if (!dev->warm) {
|
|
ret = -EAGAIN;
|
|
goto err;
|
|
}
|
|
|
|
if(dev->config.RF_switch)
|
|
dev->config.RF_switch(i2c,dev->config.num,0); //
|
|
if(dev->config.TS_switch)
|
|
dev->config.TS_switch(i2c,1); //
|
|
|
|
if(dev->config.LED_switch)
|
|
dev->config.LED_switch(i2c,2); //
|
|
|
|
mutex_lock(&dev->base->i2c_mutex);
|
|
|
|
symbol_rate_KSs = c->symbol_rate / 1000;
|
|
realFreq = c->frequency;
|
|
/*reset */
|
|
ret = regmap_multi_reg_write(dev->regmap, reset_buf, 2);
|
|
if (ret)
|
|
goto err;
|
|
|
|
msleep(2);
|
|
/*clear ts */
|
|
regmap_write(dev->regmap, 0xf5, 0x00);
|
|
regmap_read(dev->regmap, 0xfd, &tmp);
|
|
regmap_read(dev->regmap, 0xb2, &tmp);
|
|
if (tmp == 0x01) {
|
|
regmap_write(dev->regmap, 0x00, 0x0);
|
|
regmap_write(dev->regmap, 0xb2, 0x0);
|
|
}
|
|
if (c->symbol_rate < 5000000) {
|
|
lpf_offset_KHz = 3000;
|
|
realFreq = c->frequency + 3000;
|
|
}
|
|
|
|
regmap_write(dev->regmap, 0x6, 0xe0);
|
|
rs6060_select_mclk(dev, realFreq / 1000, symbol_rate_KSs);
|
|
if (dev->mclk == 93000)
|
|
regmap_write(dev->regmap, 0xa0, 0x42);
|
|
else if (dev->mclk == 96000)
|
|
regmap_write(dev->regmap, 0xa0, 0x44);
|
|
else if (dev->mclk == 99000)
|
|
regmap_write(dev->regmap, 0xa0, 0x46);
|
|
else if (dev->mclk == 110250)
|
|
regmap_write(dev->regmap, 0xa0, 0x4e);
|
|
else
|
|
regmap_write(dev->regmap, 0xa0, 0x44);
|
|
|
|
regmap_read(dev->regmap, 0xfd, &tmp);
|
|
rs6060_set_ts_mclk(dev, target_mclk);
|
|
regmap_write(dev->regmap, 0x6, 0x0);
|
|
msleep(10);
|
|
|
|
rs6060_set_reg(dev, 0x5b, 0x4c);
|
|
rs6060_set_reg(dev, 0x5c, 0x54);
|
|
rs6060_set_reg(dev, 0x60, 0x4b);
|
|
//set tuner pll
|
|
ret = rs6060_set_pll_freq(dev, (realFreq + 500) / 1000);
|
|
if (ret)
|
|
goto err;
|
|
ret = rs6060_set_bb(dev, symbol_rate_KSs, lpf_offset_KHz);
|
|
if (ret)
|
|
goto err;
|
|
|
|
rs6060_set_reg(dev, 0x00, 0x1);
|
|
rs6060_set_reg(dev, 0x00, 0x0);
|
|
|
|
regmap_write(dev->regmap, 0xb2, 0x1);
|
|
regmap_write(dev->regmap, 0x00, 0x1);
|
|
|
|
for (i = 0; i < (sizeof(rs6060_reg_tbl_def) / 2); i++)
|
|
ret =
|
|
regmap_write(dev->regmap, rs6060_reg_tbl_def[i].reg,
|
|
rs6060_reg_tbl_def[i].val);
|
|
|
|
if (ret)
|
|
goto err;
|
|
|
|
if ((symbol_rate_KSs > 47100) && (symbol_rate_KSs < 47500)) {
|
|
regmap_write(dev->regmap, 0xe6, 0x00);
|
|
regmap_write(dev->regmap, 0xe7, 0x03);
|
|
}
|
|
|
|
regmap_read(dev->regmap, 0x4d, &tmp);
|
|
tmp &= (~0x2);
|
|
regmap_write(dev->regmap, 0x4d, tmp);
|
|
|
|
regmap_read(dev->regmap, 0x08, &tmp);
|
|
regmap_write(dev->regmap, 0x08, tmp & 0x7f);
|
|
|
|
regmap_read(dev->regmap, 0xc9, &tmp);
|
|
regmap_write(dev->regmap, 0xc9, tmp | 0x8);
|
|
|
|
if (symbol_rate_KSs <= 3000)
|
|
tmp = 0x20;
|
|
else if (symbol_rate_KSs <= 10000)
|
|
tmp = 0x10;
|
|
else
|
|
tmp = 0x6;
|
|
|
|
regmap_write(dev->regmap, 0xc3, 0x8);
|
|
regmap_write(dev->regmap, 0xc8, tmp);
|
|
regmap_write(dev->regmap, 0xc4, 0x8);
|
|
regmap_write(dev->regmap, 0xc7, 0x0);
|
|
|
|
u32tmp = ((symbol_rate_KSs << 15) + (dev->mclk / 4)) / (dev->mclk / 2);
|
|
|
|
regmap_write(dev->regmap, 0x61, (u8) (u32tmp & 0xff));
|
|
regmap_write(dev->regmap, 0x62, (u8) ((u32tmp >> 8) & 0xff));
|
|
|
|
regmap_read(dev->regmap, 0x76, &tmp);
|
|
regmap_write(dev->regmap, 0x76, 0x30);
|
|
|
|
regmap_write(dev->regmap, 0x22, pls[0]);
|
|
regmap_write(dev->regmap, 0x23, pls[1]);
|
|
regmap_write(dev->regmap, 0x24, pls[2]);
|
|
|
|
regmap_read(dev->regmap, 0x08, &tmp);
|
|
switch (c->delivery_system) {
|
|
case SYS_DVBS:
|
|
tmp = (tmp & 0xfb) | 0x40;
|
|
regmap_write(dev->regmap, 0x08, tmp);
|
|
regmap_write(dev->regmap, 0xe0, 0xf8);
|
|
break;
|
|
case SYS_DVBS2:
|
|
tmp |= 0x44;
|
|
regmap_write(dev->regmap, 0x08, tmp);
|
|
break;
|
|
default:
|
|
tmp &= 0xbb;
|
|
regmap_write(dev->regmap, 0x08, tmp);
|
|
regmap_write(dev->regmap, 0xe0, 0xf8);
|
|
}
|
|
|
|
// regmap_write(dev->regmap, 0x08, 3);
|
|
// regmap_write(dev->regmap, 0xe0, 0xf8);
|
|
|
|
s32tmp = 0x10000 * lpf_offset_KHz;
|
|
s32tmp = (2 * s32tmp + dev->mclk) / (2 * dev->mclk);
|
|
buf[0] = (s32tmp >> 0) & 0xff;
|
|
buf[1] = (s32tmp >> 8) & 0xff;
|
|
//ret = regmap_bulk_write(dev->regmap, 0x5e, buf, 2);
|
|
ret = regmap_write(dev->regmap, 0x5e, buf[0]);
|
|
ret = regmap_write(dev->regmap, 0x5f, buf[1]);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_write(dev->regmap, 0x00, 0x00);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_write(dev->regmap, 0xb2, 0x00);
|
|
if (ret)
|
|
goto err;
|
|
|
|
|
|
// ret = regmap_write(dev->regmap, 0xfe, 0xe1);
|
|
// if (ret)
|
|
// goto err;
|
|
|
|
// ret = regmap_write(dev->regmap, 0xea, 0x4);
|
|
//if (ret)
|
|
// goto err;
|
|
if (c->stream_id != NO_STREAM_ID_FILTER) {
|
|
isi = c->stream_id & 0xff;
|
|
pls_mode = (c->stream_id >> 26) & 3;
|
|
pls_code = (c->stream_id >> 8) & 0x3ffff;
|
|
if (!pls_mode && !pls_code)
|
|
pls_code = 1;
|
|
} else {
|
|
isi = 0;
|
|
pls_mode = 0;
|
|
pls_code = 1;
|
|
}
|
|
|
|
if (c->scrambling_sequence_index) {
|
|
pls_mode = 1;
|
|
pls_code = c->scrambling_sequence_index;
|
|
}
|
|
|
|
if (pls_mode)
|
|
m88rs6060_calc_PLS_gold_code(pls, pls_code);
|
|
else {
|
|
pls[0] = pls_code & 0xff;
|
|
pls[1] = (pls_code >> 8) & 0xff;
|
|
pls[2] = (pls_code >> 16) & 3;
|
|
}
|
|
|
|
dev_dbg(&i2c->dev, "isi = %d", isi);
|
|
dev_dbg(&i2c->dev, "pls mode %d, code %d\n", pls_mode, pls_code);
|
|
dev_dbg(&i2c->dev, "pls buf =%*ph \n", 3, pls);
|
|
|
|
ret = regmap_bulk_write(dev->regmap, 0x22, pls, 3);
|
|
|
|
rs6060_set_reg(dev, 0x5b, 0xcc);
|
|
rs6060_set_reg(dev, 0x5c, 0xf4);
|
|
rs6060_set_reg(dev, 0x60, 0xcb);
|
|
|
|
for (i = 0; i < 150; i++) {
|
|
regmap_read(dev->regmap, 0x8, &tmp);
|
|
regmap_read(dev->regmap, 0xd, &tmp1);
|
|
|
|
if ((tmp1 == 0x8f) || (tmp1 == 0xf7))
|
|
break;
|
|
msleep(20);
|
|
}
|
|
|
|
if (tmp1 == 0x8f) {
|
|
regmap_read(dev->regmap, 0x89, &tmp);
|
|
regmap_read(dev->regmap, 0xca, &tmp1);
|
|
tmp &= 0x80;
|
|
regmap_write(dev->regmap, 0xca,
|
|
(u8) ((tmp1 & 0xf7) | (tmp >> 4) | 0x02));
|
|
regmap_write(dev->regmap, 0xfa, 0x00);
|
|
regmap_write(dev->regmap, 0xf0, 0x00);
|
|
regmap_write(dev->regmap, 0xf0, 0x03);
|
|
|
|
msleep(20);
|
|
regmap_read(dev->regmap, 0xf1, &tmp1);
|
|
tmp1 &= 0x1f;
|
|
dev_dbg(&i2c->dev, "ISI cnt = %d \n", tmp1);
|
|
for (j = 0; j < tmp1; j++) {
|
|
regmap_write(dev->regmap, 0xf2, j);
|
|
regmap_read(dev->regmap, 0xf3, &tsid[j]);
|
|
dev_dbg(&i2c->dev, "ISI = %d \n", tsid[j]);
|
|
}
|
|
for (j = 0; j < tmp1; j++)
|
|
if (tsid[j] == isi) {
|
|
mis = true;
|
|
break;
|
|
}
|
|
|
|
if (mis)
|
|
regmap_write(dev->regmap, 0xf5, isi);
|
|
else
|
|
regmap_write(dev->regmap, 0xf5, tsid[0]);
|
|
}
|
|
|
|
dev->TsClockChecked = true;
|
|
|
|
if(dev->config.HAS_CI)
|
|
dev->newTP = true;
|
|
|
|
mutex_unlock(&dev->base->i2c_mutex);
|
|
return 0;
|
|
|
|
err:
|
|
mutex_unlock(&dev->base->i2c_mutex);
|
|
dev_dbg(&i2c->dev, "failed = %d", ret);
|
|
return ret;
|
|
}
|
|
|
|
static enum dvbfe_algo m88rs6060_get_algo(struct dvb_frontend *fe)
|
|
{
|
|
return DVBFE_ALGO_HW;
|
|
}
|
|
|
|
static int m88rs6060_init(struct dvb_frontend *fe)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
|
|
/*warm state */
|
|
dev->warm = true;
|
|
|
|
//
|
|
c->cnr.len = 1;
|
|
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
c->post_bit_error.len = 1;
|
|
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
c->post_bit_count.len = 1;
|
|
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
|
|
//dev_info(&i2c->dev, "%s finished\n", __func__);
|
|
|
|
return 0;
|
|
|
|
}
|
|
static int m88rs6060_get_sym_rate(struct m88rs6060_dev *dev,
|
|
u32 *sym_rate_KSs)
|
|
{
|
|
u16 tmp;
|
|
u32 sym_rate_tmp;
|
|
unsigned val_0x6d,val_0x6e;
|
|
|
|
regmap_read(dev->regmap,0x6d,&val_0x6d);
|
|
regmap_read(dev->regmap,0x6e,&val_0x6e);
|
|
|
|
tmp = (u16)((val_0x6e<<8)|val_0x6d);
|
|
sym_rate_tmp = tmp*dev->mclk;
|
|
sym_rate_tmp /= (1<<16);
|
|
*sym_rate_KSs = sym_rate_tmp;
|
|
|
|
return 0;
|
|
}
|
|
static int m88rs6060_get_channel_info(struct m88rs6060_dev *dev,
|
|
struct MT_FE_CHAN_INFO_DVBS2*p_info)
|
|
{
|
|
unsigned tmp,val_0x17,val_0x18,ucPLSCode;
|
|
|
|
regmap_read(dev->regmap,0x08,&tmp);
|
|
if((tmp&0x08)==0x08){ //dvbs2 signal
|
|
|
|
p_info->type = MtFeType_DvbS2;
|
|
|
|
regmap_write(dev->regmap,0x8a,0x01);
|
|
regmap_read(dev->regmap,0x17,&val_0x17);
|
|
p_info->is_dummy_frame = (val_0x17&0x40)?true:false;
|
|
|
|
regmap_read(dev->regmap,0x18,&val_0x18);
|
|
tmp = (val_0x18>>5) & 0x07;
|
|
switch(tmp){
|
|
case 1: p_info->mod_mode = MtFeModMode_8psk; break;
|
|
case 2: p_info->mod_mode = MtFeModMode_16Apsk; break;
|
|
case 3: p_info->mod_mode = MtFeModMode_32Apsk; break;
|
|
case 4: p_info->mod_mode = MtFeModMode_64Apsk; break;
|
|
case 5: p_info->mod_mode = MtFeModMode_128Apsk; break;
|
|
case 6:
|
|
case 7: p_info->mod_mode = MtFeModMode_256Apsk; break;
|
|
case 0:
|
|
default: p_info->mod_mode = MtFeModMode_Qpsk; break;
|
|
|
|
}
|
|
p_info->iVcmCycle = val_0x18 &0x1F;
|
|
regmap_read(dev->regmap,0x19,&ucPLSCode);
|
|
p_info->iPlsCode = ucPLSCode;
|
|
p_info->type = mPLSInfoTable[ucPLSCode].mDvbType;
|
|
|
|
if(mPLSInfoTable[ucPLSCode].bValid){
|
|
p_info->mod_mode = mPLSInfoTable[ucPLSCode].mModMode;
|
|
p_info->code_rate = mPLSInfoTable[ucPLSCode].mCodeRate;
|
|
p_info->is_dummy_frame = mPLSInfoTable[ucPLSCode].bDummyFrame;
|
|
p_info->is_pilot_on = mPLSInfoTable[ucPLSCode].bPilotOn;
|
|
p_info->iFrameLength = mPLSInfoTable[ucPLSCode].iFrameLength;
|
|
|
|
}else{
|
|
//p_info->mod_mode = mPLSInfoTable[ucPLSCode].mModMode;
|
|
p_info->code_rate = mPLSInfoTable[ucPLSCode].mCodeRate;
|
|
//p_info->is_dummy_frame = mPLSInfoTable[ucPLSCode].bDummyFrame;
|
|
p_info->is_pilot_on = mPLSInfoTable[ucPLSCode].bPilotOn;
|
|
p_info->iFrameLength = mPLSInfoTable[ucPLSCode].iFrameLength;
|
|
|
|
}
|
|
|
|
regmap_read(dev->regmap,0x89,&tmp);
|
|
p_info->is_spectrum_inv =
|
|
((tmp&0x80)!=0)? MtFeSpectrum_Inversion: MtFeSpectrum_Normal;
|
|
|
|
regmap_read(dev->regmap,0x76,&tmp);
|
|
tmp &=0x03;
|
|
if(p_info->type == MtFeType_DvbS2X){ //dvbs2x
|
|
switch(tmp){
|
|
case 0 : p_info->roll_off = MtFeRollOff_0p15;break;
|
|
case 1 : p_info->roll_off = MtFeRollOff_0p10;break;
|
|
case 2 : p_info->roll_off = MtFeRollOff_0p05;break;
|
|
default : p_info->roll_off = MtFeRollOff_Undef;break;
|
|
|
|
}
|
|
}else{ //dvbs2
|
|
switch(tmp){
|
|
case 0 : p_info->roll_off = MtFeRollOff_0p35;break;
|
|
case 1 : p_info->roll_off = MtFeRollOff_0p25;break;
|
|
case 2 : p_info->roll_off = MtFeRollOff_0p20;break;
|
|
default : p_info->roll_off = MtFeRollOff_Undef;break;
|
|
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
p_info->type = MtFeType_DvbS;
|
|
p_info->mod_mode = MtFeModMode_Qpsk;
|
|
|
|
regmap_read(dev->regmap,0xe6,&tmp);
|
|
tmp= (u8)tmp>>5;
|
|
switch(tmp){
|
|
case 0 : p_info->code_rate = MtFeCodeRate_7_8;break;
|
|
case 1 : p_info->code_rate = MtFeCodeRate_5_6;break;
|
|
case 2 : p_info->code_rate = MtFeCodeRate_3_4;break;
|
|
case 3 : p_info->code_rate = MtFeCodeRate_2_3;break;
|
|
case 4 : p_info->code_rate = MtFeCodeRate_1_2;break;
|
|
default : p_info->code_rate = MtFeCodeRate_Undef;break;
|
|
}
|
|
p_info->is_pilot_on = false;
|
|
regmap_read(dev->regmap,0xe0,&tmp);
|
|
p_info->is_spectrum_inv =
|
|
((tmp&0x40)!=0)? MtFeSpectrum_Inversion: MtFeSpectrum_Normal;
|
|
p_info->roll_off = MtFeRollOff_0p35;
|
|
p_info->is_dummy_frame = false;
|
|
p_info->iVcmCycle = -1;
|
|
p_info->iPlsCode = 0;
|
|
p_info->iFrameLength = 0;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int rs6060_select_xm(struct m88rs6060_dev*dev,u32 *xm_KHz)
|
|
{
|
|
u32 symbol_rate = 0;
|
|
u8 reg16;
|
|
u32 offset_KHz[8] = {0};
|
|
u32 max_offset = 0;
|
|
u8 i, xm_line, xm_cnt = 5;
|
|
u32 xm_list_KHz[3][8] = {
|
|
{96000, 102400, 107162, 109714, 115200, 128000, 135529, 144000},
|
|
{93000, 99200, 111600, 117473, 124000, 139500, 144000, 148800},
|
|
{99000, 105600, 108000, 110511, 118800, 132000, 144000, 148500}
|
|
};
|
|
|
|
|
|
|
|
m88rs6060_get_sym_rate(dev,&symbol_rate);
|
|
xm_cnt = sizeof(xm_list_KHz) / sizeof(u32);
|
|
xm_cnt /= 3;
|
|
// C = (symbol * 1.35 / 2 + 2) * 1.1;
|
|
symbol_rate *= 135;
|
|
symbol_rate /= 200;
|
|
symbol_rate += 2000;
|
|
symbol_rate *= 110;
|
|
symbol_rate /= 100;
|
|
|
|
reg16 = rs6060_get_reg(dev, 0x16);
|
|
|
|
if(reg16 == 92){
|
|
xm_line = 1;
|
|
}
|
|
else if(reg16 == 100){
|
|
xm_line = 2;
|
|
}
|
|
else{//if(reg16 == 96)
|
|
xm_line = 0;
|
|
}
|
|
|
|
for(i = 0; i < xm_cnt; i ++){
|
|
if(*xm_KHz > xm_list_KHz[xm_line][i])
|
|
{
|
|
continue;
|
|
}
|
|
offset_KHz[i] = (dev->frequecy % xm_list_KHz[xm_line][i]);
|
|
if(offset_KHz[i] > (xm_list_KHz[xm_line][i] / 2))
|
|
offset_KHz[i] = xm_list_KHz[xm_line][i] - offset_KHz[i];
|
|
if(offset_KHz[i] > symbol_rate)
|
|
{
|
|
*xm_KHz = xm_list_KHz[xm_line][i];
|
|
break;
|
|
}
|
|
if(offset_KHz[i] > max_offset)
|
|
{
|
|
max_offset = offset_KHz[i];
|
|
*xm_KHz = xm_list_KHz[xm_line][i];
|
|
}
|
|
}
|
|
|
|
if(i == xm_cnt)
|
|
{
|
|
*xm_KHz = xm_list_KHz[xm_line][xm_cnt - 1];
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int m88rs6060_set_clock_ratio(struct m88rs6060_dev *dev )
|
|
{
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
unsigned mod_fac,tmp1,tmp2,val;
|
|
u32 input_datarate,locked_sym_rate_KSs;
|
|
u32 Mclk_KHz = 96000,iSerialMclkHz;
|
|
u16 divid_ratio = 0;
|
|
struct MT_FE_CHAN_INFO_DVBS2 p_info;
|
|
|
|
m88rs6060_get_sym_rate(dev,&locked_sym_rate_KSs);
|
|
|
|
regmap_read(dev->regmap,0x9d,&val);
|
|
regmap_write(dev->regmap,0x9d,val|0x08);
|
|
|
|
m88rs6060_get_channel_info(dev,&p_info);
|
|
|
|
if(p_info.type==MtFeType_DvbS2 || p_info.type == MtFeType_DvbS2X){
|
|
dev_dbg(&i2c->dev, "iPlsCode = 0x%02X\n", p_info.iPlsCode);
|
|
switch(p_info.mod_mode)
|
|
{
|
|
case MtFeModMode_8psk:
|
|
case MtFeModMode_8Apsk_L: mod_fac = 3; break;
|
|
case MtFeModMode_16Apsk:
|
|
case MtFeModMode_16Apsk_L: mod_fac = 4; break;
|
|
case MtFeModMode_32Apsk:
|
|
case MtFeModMode_32Apsk_L: mod_fac = 5; break;
|
|
case MtFeModMode_64Apsk:
|
|
case MtFeModMode_64Apsk_L: mod_fac = 6; break;
|
|
case MtFeModMode_128Apsk:
|
|
case MtFeModMode_128Apsk_L: mod_fac = 7; break;
|
|
case MtFeModMode_256Apsk:
|
|
case MtFeModMode_256Apsk_L: mod_fac = 8; break;
|
|
case MtFeModMode_Qpsk:
|
|
default: mod_fac = 2; break;
|
|
}
|
|
switch(p_info.code_rate)
|
|
{
|
|
case MtFeCodeRate_1_4: input_datarate = locked_sym_rate_KSs*mod_fac/8/4; break;
|
|
case MtFeCodeRate_1_3: input_datarate = locked_sym_rate_KSs*mod_fac/8/3; break;
|
|
case MtFeCodeRate_2_5: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/5; break;
|
|
case MtFeCodeRate_1_2: input_datarate = locked_sym_rate_KSs*mod_fac/8/2; break;
|
|
case MtFeCodeRate_3_5: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/5; break;
|
|
case MtFeCodeRate_2_3: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break;
|
|
case MtFeCodeRate_3_4: input_datarate = locked_sym_rate_KSs*mod_fac*3/8/4; break;
|
|
case MtFeCodeRate_4_5: input_datarate = locked_sym_rate_KSs*mod_fac*4/8/5; break;
|
|
case MtFeCodeRate_5_6: input_datarate = locked_sym_rate_KSs*mod_fac*5/8/6; break;
|
|
case MtFeCodeRate_8_9: input_datarate = locked_sym_rate_KSs*mod_fac*8/8/9; break;
|
|
case MtFeCodeRate_9_10: input_datarate = locked_sym_rate_KSs*mod_fac*9/8/10; break;
|
|
case MtFeCodeRate_5_9: input_datarate = locked_sym_rate_KSs*mod_fac*5/8/9; break;
|
|
case MtFeCodeRate_7_9: input_datarate = locked_sym_rate_KSs*mod_fac*7/8/9; break;
|
|
case MtFeCodeRate_4_15: input_datarate = locked_sym_rate_KSs*mod_fac*4/8/15; break;
|
|
case MtFeCodeRate_7_15: input_datarate = locked_sym_rate_KSs*mod_fac*7/8/15; break;
|
|
case MtFeCodeRate_8_15: input_datarate = locked_sym_rate_KSs*mod_fac*8/8/15; break;
|
|
case MtFeCodeRate_11_15: input_datarate = locked_sym_rate_KSs*mod_fac*11/8/15; break;
|
|
case MtFeCodeRate_13_18: input_datarate = locked_sym_rate_KSs*mod_fac*13/8/18; break;
|
|
case MtFeCodeRate_9_20: input_datarate = locked_sym_rate_KSs*mod_fac*9/8/20; break;
|
|
case MtFeCodeRate_11_20: input_datarate = locked_sym_rate_KSs*mod_fac*11/8/20; break;
|
|
case MtFeCodeRate_23_36: input_datarate = locked_sym_rate_KSs*mod_fac*23/8/36; break;
|
|
case MtFeCodeRate_25_36: input_datarate = locked_sym_rate_KSs*mod_fac*25/8/36; break;
|
|
case MtFeCodeRate_11_45: input_datarate = locked_sym_rate_KSs*mod_fac*11/8/45; break;
|
|
case MtFeCodeRate_13_45: input_datarate = locked_sym_rate_KSs*mod_fac*13/8/45; break;
|
|
case MtFeCodeRate_14_45: input_datarate = locked_sym_rate_KSs*mod_fac*14/8/45; break;
|
|
case MtFeCodeRate_26_45: input_datarate = locked_sym_rate_KSs*mod_fac*26/8/45; break;
|
|
case MtFeCodeRate_28_45: input_datarate = locked_sym_rate_KSs*mod_fac*28/8/45; break;
|
|
case MtFeCodeRate_29_45: input_datarate = locked_sym_rate_KSs*mod_fac*29/8/45; break;
|
|
case MtFeCodeRate_31_45: input_datarate = locked_sym_rate_KSs*mod_fac*31/8/45; break;
|
|
case MtFeCodeRate_32_45: input_datarate = locked_sym_rate_KSs*mod_fac*32/8/45; break;
|
|
case MtFeCodeRate_77_90: input_datarate = locked_sym_rate_KSs*mod_fac*77/8/90; break;
|
|
default: input_datarate = locked_sym_rate_KSs*mod_fac*2/8/3; break;
|
|
|
|
}
|
|
|
|
rs6060_get_ts_mclk(dev,&Mclk_KHz);
|
|
if(dev->config.ts_mode==MtFeTsOutMode_Serial){
|
|
u32 target_mclk = Mclk_KHz;
|
|
input_datarate*=8;
|
|
|
|
target_mclk = input_datarate;
|
|
rs6060_select_xm(dev,&target_mclk);
|
|
if(target_mclk != Mclk_KHz){
|
|
regmap_write(dev->regmap,0x06,0xe0);
|
|
rs6060_set_ts_mclk(dev,target_mclk);
|
|
regmap_write(dev->regmap,0x06,0x00);
|
|
}
|
|
|
|
rs6060_get_ts_mclk(dev,&iSerialMclkHz);
|
|
if(iSerialMclkHz>116000)
|
|
regmap_write(dev->regmap,0x0a,0x01);
|
|
else
|
|
regmap_write(dev->regmap,0x0a,0x00);
|
|
}else{
|
|
iSerialMclkHz = input_datarate*49/5;
|
|
input_datarate = input_datarate *105/100;
|
|
if(iSerialMclkHz>115200)
|
|
iSerialMclkHz = 144000;
|
|
else if(iSerialMclkHz>96000)
|
|
iSerialMclkHz = 115200;
|
|
else if(iSerialMclkHz>72000)
|
|
iSerialMclkHz = 96000;
|
|
else
|
|
iSerialMclkHz = 72000;
|
|
if(input_datarate<6000)
|
|
input_datarate= 6000;
|
|
if(input_datarate != 0)
|
|
divid_ratio = (u16) (Mclk_KHz/input_datarate);
|
|
else
|
|
divid_ratio = 0xff;
|
|
dev_dbg(&i2c->dev, "MClk_KHz = %d,divid_ratio = %d \n", Mclk_KHz, divid_ratio);
|
|
|
|
if(divid_ratio<8)
|
|
divid_ratio = 8;
|
|
if(dev->config.ts_mode == MtFeTsOutMode_Common){
|
|
if(divid_ratio>27)
|
|
divid_ratio = 27;
|
|
if((divid_ratio == 14)||(divid_ratio==15))
|
|
divid_ratio = 13;
|
|
if((divid_ratio == 19)||(divid_ratio == 20))
|
|
divid_ratio = 18;
|
|
}else{
|
|
if(divid_ratio>24)
|
|
divid_ratio = 24;
|
|
if((divid_ratio == 12)||(divid_ratio==13))
|
|
divid_ratio = 11;
|
|
if((divid_ratio == 19)||(divid_ratio == 20))
|
|
divid_ratio = 18;
|
|
}
|
|
tmp1 = (u8) ((divid_ratio/2)-1);
|
|
tmp2 = DIV_ROUND_UP(divid_ratio,2)-1;
|
|
tmp1 &= 0x3f;
|
|
tmp2 &= 0x3f;
|
|
val = (tmp1 >>2)&0x0f;
|
|
regmap_update_bits(dev->regmap,0xfe,0x0f,val);
|
|
val = (u8)(((tmp1&0x3)<<6)|tmp2);
|
|
regmap_write(dev->regmap,0xea,val);
|
|
}
|
|
}
|
|
else{ //dvbs
|
|
mod_fac = 2;
|
|
switch(p_info.code_rate){
|
|
case MtFeCodeRate_1_2: input_datarate = locked_sym_rate_KSs*mod_fac/2/8; break;
|
|
case MtFeCodeRate_2_3: input_datarate = locked_sym_rate_KSs*mod_fac*2/3/8; break;
|
|
case MtFeCodeRate_3_4: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break;
|
|
case MtFeCodeRate_5_6: input_datarate = locked_sym_rate_KSs*mod_fac*5/6/8; break;
|
|
case MtFeCodeRate_7_8: input_datarate = locked_sym_rate_KSs*mod_fac*7/8/8; break;
|
|
default: input_datarate = locked_sym_rate_KSs*mod_fac*3/4/8; break;
|
|
}
|
|
rs6060_get_ts_mclk(dev,&Mclk_KHz);
|
|
|
|
if(dev->config.ts_mode==MtFeTsOutMode_Serial){
|
|
u32 target_mclk = Mclk_KHz;
|
|
input_datarate*=8;
|
|
|
|
// target_mclk = input_datarate;
|
|
rs6060_select_xm(dev,&target_mclk);
|
|
if(target_mclk != Mclk_KHz){
|
|
regmap_write(dev->regmap,0x06,0xe0);
|
|
rs6060_set_ts_mclk(dev,target_mclk);
|
|
regmap_write(dev->regmap,0x06,0x00);
|
|
}
|
|
|
|
rs6060_get_ts_mclk(dev,&iSerialMclkHz);
|
|
if(iSerialMclkHz>116000)
|
|
regmap_write(dev->regmap,0x0a,0x01);
|
|
else
|
|
regmap_write(dev->regmap,0x0a,0x00);
|
|
|
|
}else{
|
|
iSerialMclkHz = input_datarate*46/5;
|
|
input_datarate = input_datarate *105/100;
|
|
|
|
if(iSerialMclkHz>72000)
|
|
iSerialMclkHz = 96000;
|
|
else
|
|
iSerialMclkHz = 72000;
|
|
|
|
if(input_datarate<6000)
|
|
input_datarate = 6000;
|
|
if(input_datarate != 0)
|
|
divid_ratio = (u16)(Mclk_KHz/input_datarate);
|
|
else
|
|
divid_ratio = 0xff;
|
|
if(divid_ratio<8)
|
|
divid_ratio = 8;
|
|
if(dev->config.ts_mode == MtFeTsOutMode_Common){
|
|
if(divid_ratio>27)
|
|
divid_ratio=27;
|
|
}
|
|
else {
|
|
if (divid_ratio>24)
|
|
divid_ratio =24;
|
|
}
|
|
tmp1 = (u8)((divid_ratio/2)-1);
|
|
tmp2 = DIV_ROUND_UP(divid_ratio,2)-1;
|
|
|
|
tmp1 &= 0x3f;
|
|
tmp2 &= 0x3f;
|
|
val = (tmp1 >>2)&0x0f;
|
|
regmap_update_bits(dev->regmap,0xfe,0x0f,val);
|
|
val = (u8)(((tmp1&0x3)<<6)|tmp2);
|
|
regmap_write(dev->regmap,0xea,val);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
static int m88rs6060_read_status(struct dvb_frontend *fe,
|
|
enum fe_status *status)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
|
|
int ret, i, itmp;
|
|
unsigned int utmp;
|
|
u8 buf[3];
|
|
s32 gain;
|
|
u16 temp;
|
|
dev_dbg(&i2c->dev, "%s\n", __func__);
|
|
|
|
*status = 0;
|
|
|
|
if (!dev->warm) {
|
|
ret = -EAGAIN;
|
|
goto err;
|
|
}
|
|
mutex_lock(&dev->base->i2c_mutex);
|
|
switch (c->delivery_system) {
|
|
case SYS_DVBS:
|
|
ret = regmap_read(dev->regmap, 0x0d, &utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if ((utmp & 0xf7) == 0xf7)
|
|
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
|
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
|
break;
|
|
case SYS_DVBS2:
|
|
ret = regmap_read(dev->regmap, 0x0d, &utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if ((utmp & 0x8f) == 0x8f)
|
|
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
|
|
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
|
|
break;
|
|
default:
|
|
dev_dbg(&i2c->dev, "invalid delivery_system\n");
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
dev->fe_status = *status;
|
|
dev_dbg(&i2c->dev, "lock=%02x status=%02x\n", utmp, *status);
|
|
|
|
if ((!dev->config.ts_autoclock)&&(dev->fe_status & FE_HAS_LOCK)&&(dev->TsClockChecked)){
|
|
dev->TsClockChecked = false;
|
|
dev->frequecy = c->frequency;
|
|
m88rs6060_set_clock_ratio(dev);
|
|
}
|
|
|
|
if((dev->config.HAS_CI)&&(dev->fe_status & FE_HAS_LOCK)&&(dev->newTP))
|
|
{
|
|
mutex_lock(&dev->priv->base1->i2c_mutex_ci);
|
|
u32 value;
|
|
u32 clock;
|
|
clock = dev->config.SetCIClock(i2c,dev->config.num);
|
|
value = (clock/8*204/188*25000/6)+500;
|
|
// printk("clk port = %d,clock = %d,value=%d\n",dev->priv->clk_port,clock,value);
|
|
si5351_set_freq(dev->priv,value,0,dev->priv->clk_port);
|
|
mutex_unlock(&dev->priv->base1->i2c_mutex_ci);
|
|
dev->newTP = false;
|
|
}
|
|
/*power of rf signal */
|
|
m88rs6060_get_gain(dev, c->frequency / 1000, &gain);
|
|
c->strength.len = 2;
|
|
c->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
|
c->strength.stat[0].svalue = -gain * 10;
|
|
|
|
c->strength.stat[1].scale = FE_SCALE_RELATIVE;
|
|
c->strength.stat[1].svalue = (100 + (-gain / 100)) * 656;
|
|
|
|
c->cnr.len = 1;
|
|
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
|
|
if (dev->fe_status & FE_HAS_VITERBI) {
|
|
unsigned int cnr, noise, signal, noise_tot, signal_tot;
|
|
|
|
cnr = 0;
|
|
/* more iterations for more accurate estimation */
|
|
#define M88rs6060_SNR_ITERATIONS 10
|
|
|
|
switch (c->delivery_system) {
|
|
case SYS_DVBS:
|
|
itmp = 0;
|
|
|
|
for (i = 0; i < M88rs6060_SNR_ITERATIONS; i++) {
|
|
ret = regmap_read(dev->regmap, 0xff, &utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
itmp += utmp;
|
|
}
|
|
temp = (u16) (itmp / 80);
|
|
|
|
if (temp > 32)
|
|
temp = 32;
|
|
if (temp > 1)
|
|
cnr = (mes_loge[temp - 1] * 10) / 23;
|
|
else
|
|
cnr = 0;
|
|
break;
|
|
case SYS_DVBS2:
|
|
noise_tot = 0;
|
|
signal_tot = 0;
|
|
|
|
for (i = 0; i < M88rs6060_SNR_ITERATIONS; i++) {
|
|
ret =
|
|
regmap_bulk_read(dev->regmap, 0x8c, buf, 3);
|
|
if (ret)
|
|
goto err;
|
|
|
|
noise = buf[1] << 6; /* [13:6] */
|
|
noise |= buf[0] & 0x3f; /* [5:0] */
|
|
noise >>= 2;
|
|
signal = buf[2] * buf[2];
|
|
signal >>= 1;
|
|
|
|
noise_tot += noise;
|
|
signal_tot += signal;
|
|
}
|
|
|
|
noise = noise_tot / M88rs6060_SNR_ITERATIONS;
|
|
signal = signal_tot / M88rs6060_SNR_ITERATIONS;
|
|
if (signal == 0)
|
|
cnr = 0;
|
|
else if (noise == 0)
|
|
cnr = 19;
|
|
else if (signal > noise) {
|
|
itmp = signal / noise;
|
|
if (itmp > 80)
|
|
itmp = 80;
|
|
cnr = mes_log10[itmp - 1];
|
|
} else if (signal < noise) {
|
|
itmp = noise / signal;
|
|
if (itmp > 80)
|
|
itmp = 80;
|
|
cnr = mes_log10[itmp - 1];
|
|
}
|
|
break;
|
|
default:
|
|
dev_dbg(&i2c->dev, "invalid delivery_system\n");
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
c->cnr.len = 2;
|
|
c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
|
c->cnr.stat[0].svalue = cnr;
|
|
c->cnr.stat[1].scale = FE_SCALE_RELATIVE;
|
|
c->cnr.stat[1].uvalue = (cnr/100) * 328;
|
|
if (c->cnr.stat[1].uvalue > 0xffff)
|
|
c->cnr.stat[1].uvalue = 0xffff;
|
|
}
|
|
|
|
/* BER */
|
|
if (dev->fe_status & FE_HAS_LOCK) {
|
|
unsigned int utmp, post_bit_error, post_bit_count;
|
|
|
|
switch (c->delivery_system) {
|
|
case SYS_DVBS:
|
|
|
|
ret = regmap_read(dev->regmap, 0xd5, &utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
/* measurement ready? */
|
|
if (!(utmp & 0x10)) {
|
|
ret =
|
|
regmap_bulk_read(dev->regmap, 0xd6, buf, 2);
|
|
if (ret)
|
|
goto err;
|
|
|
|
post_bit_error = buf[1] << 8 | buf[0] << 0;
|
|
post_bit_count = 0x800000;
|
|
dev->post_bit_error += post_bit_error;
|
|
dev->post_bit_count += post_bit_count;
|
|
dev->dvbv3_ber = post_bit_error;
|
|
|
|
/* restart measurement */
|
|
ret = regmap_write(dev->regmap, 0xd5, 0x82);
|
|
if (ret)
|
|
goto err;
|
|
}
|
|
break;
|
|
case SYS_DVBS2:
|
|
ret = regmap_bulk_read(dev->regmap, 0xd5, buf, 3);
|
|
if (ret)
|
|
goto err;
|
|
//dev_info(&i2c->dev,"buf =%*ph\n",3,buf);
|
|
utmp = buf[2] << 16 | buf[1] << 8 | buf[0] << 0;
|
|
|
|
/* enough data? */
|
|
if (utmp > 4000) {
|
|
ret =
|
|
regmap_bulk_read(dev->regmap, 0xf7, buf, 2);
|
|
if (ret)
|
|
goto err;
|
|
|
|
post_bit_error = buf[1] << 8 | buf[0] << 0;
|
|
post_bit_count = 32 * utmp; /* TODO: FEC */
|
|
dev->post_bit_error += post_bit_error;
|
|
dev->post_bit_count += post_bit_count;
|
|
dev->dvbv3_ber = post_bit_error;
|
|
|
|
/* restart measurement */
|
|
ret = regmap_write(dev->regmap, 0xd1, 0x01);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_write(dev->regmap, 0xf9, 0x01);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_write(dev->regmap, 0xf9, 0x00);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_write(dev->regmap, 0xd1, 0x00);
|
|
if (ret)
|
|
goto err;
|
|
}
|
|
break;
|
|
default:
|
|
dev_dbg(&i2c->dev, "invalid delivery_system\n");
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
|
|
c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
|
|
|
|
c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
|
|
c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
|
|
} else {
|
|
c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
|
|
}
|
|
|
|
c->post_bit_error.len = 1;
|
|
c->post_bit_count.len = 1;
|
|
|
|
mutex_unlock(&dev->base->i2c_mutex);
|
|
|
|
return 0;
|
|
err:
|
|
mutex_unlock(&dev->base->i2c_mutex);
|
|
dev_dbg(&i2c->dev, "failed=%d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static int m88rs6060_read_snr(struct dvb_frontend *fe, u16 * snr)
|
|
{
|
|
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
|
int i;
|
|
|
|
*snr = 0;
|
|
for (i=0; i < p->cnr.len; i++)
|
|
if (p->cnr.stat[i].scale == FE_SCALE_RELATIVE)
|
|
*snr = (u16)p->cnr.stat[i].uvalue;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int m88rs6060_read_ber(struct dvb_frontend *fe, u32 * ber)
|
|
{
|
|
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
|
|
|
if ( p->post_bit_error.stat[0].scale == FE_SCALE_COUNTER &&
|
|
p->post_bit_count.stat[0].scale == FE_SCALE_COUNTER )
|
|
*ber = (u32)p->post_bit_count.stat[0].uvalue ? (u32)p->post_bit_error.stat[0].uvalue /
|
|
(u32)p->post_bit_count.stat[0].uvalue : 0;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int m88rs6060_read_signal_strength(struct dvb_frontend *fe,
|
|
u16 * strength)
|
|
{
|
|
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
|
int i;
|
|
|
|
*strength = 0;
|
|
for (i=0; i < p->strength.len; i++)
|
|
if (p->strength.stat[i].scale == FE_SCALE_RELATIVE)
|
|
*strength = (u16)p->strength.stat[i].uvalue;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int m88rs6060_set_voltage(struct dvb_frontend*fe,
|
|
enum fe_sec_voltage voltage)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret;
|
|
u8 utmp;
|
|
bool voltage_sel, lnb_power;
|
|
|
|
|
|
switch(voltage){
|
|
case SEC_VOLTAGE_18:
|
|
voltage_sel = 1;
|
|
lnb_power = 1;
|
|
break;
|
|
case SEC_VOLTAGE_13:
|
|
voltage_sel = 0;
|
|
lnb_power = 1;
|
|
break;
|
|
case SEC_VOLTAGE_OFF:
|
|
voltage_sel = 0;
|
|
lnb_power = 0;
|
|
break;
|
|
}
|
|
utmp = lnb_power << 1 | voltage_sel << 0;
|
|
ret = m88rs6060_update_bits(dev, 0xa2, 0x03, utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
return 0;
|
|
err:
|
|
dev_dbg(&i2c->dev, "failed=%d\n", ret);
|
|
return ret;
|
|
|
|
}
|
|
|
|
static int m88rs6060_set_tone(struct dvb_frontend *fe,
|
|
enum fe_sec_tone_mode fe_sec_tone_mode)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret;
|
|
unsigned int utmp, tone, reg_a1_mask;
|
|
|
|
dev_dbg(&i2c->dev, "fe_sec_tone_mode=%d\n", fe_sec_tone_mode);
|
|
|
|
if (!dev->warm) {
|
|
ret = -EAGAIN;
|
|
goto err;
|
|
}
|
|
if((dev->config.num%2)&&(dev->config.disable_22k)) //for 6909se tuner 1,3,5,7 can not output 22k
|
|
return 0;
|
|
switch (fe_sec_tone_mode) {
|
|
case SEC_TONE_ON:
|
|
tone = 0;
|
|
reg_a1_mask = 0x47;
|
|
break;
|
|
case SEC_TONE_OFF:
|
|
tone = 1;
|
|
reg_a1_mask = 0x00;
|
|
break;
|
|
default:
|
|
dev_dbg(&i2c->dev, "invalid fe_sec_tone_mode\n");
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
utmp = tone << 7 | dev->config.envelope_mode << 5;
|
|
ret = m88rs6060_update_bits(dev, 0xa2, 0xe0, utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
utmp = 1 << 2;
|
|
ret = m88rs6060_update_bits(dev, 0xa1, reg_a1_mask, utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
return 0;
|
|
err:
|
|
dev_dbg(&i2c->dev, "failed=%d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static int m88rs6060_diseqc_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd
|
|
*diseqc_cmd)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret;
|
|
unsigned int utmp;
|
|
unsigned long timeout;
|
|
|
|
dev_dbg(&i2c->dev, "msg=%*ph\n",
|
|
diseqc_cmd->msg_len, diseqc_cmd->msg);
|
|
|
|
if (!dev->warm) {
|
|
ret = -EAGAIN;
|
|
goto err;
|
|
}
|
|
|
|
if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) {
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
utmp = dev->config.envelope_mode << 5;
|
|
ret = m88rs6060_update_bits(dev, 0xa2, 0xe0, utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_bulk_write(dev->regmap, 0xa3, diseqc_cmd->msg,
|
|
diseqc_cmd->msg_len);
|
|
if (ret)
|
|
goto err;
|
|
|
|
ret = regmap_write(dev->regmap, 0xa1,
|
|
(diseqc_cmd->msg_len - 1) << 3 | 0x07);
|
|
if (ret)
|
|
goto err;
|
|
|
|
/* wait DiSEqC TX ready */
|
|
#define SEND_MASTER_CMD_TIMEOUT 120
|
|
timeout = jiffies + msecs_to_jiffies(SEND_MASTER_CMD_TIMEOUT);
|
|
|
|
/* DiSEqC message period is 13.5 ms per byte */
|
|
utmp = diseqc_cmd->msg_len * 13500;
|
|
usleep_range(utmp - 4000, utmp);
|
|
|
|
for (utmp = 1; !time_after(jiffies, timeout) && utmp;) {
|
|
ret = regmap_read(dev->regmap, 0xa1, &utmp);
|
|
if (ret)
|
|
goto err;
|
|
utmp = (utmp >> 6) & 0x1;
|
|
}
|
|
|
|
if (utmp == 0) {
|
|
dev_dbg(&i2c->dev, "diseqc tx took %u ms\n",
|
|
jiffies_to_msecs(jiffies) -
|
|
(jiffies_to_msecs(timeout) - SEND_MASTER_CMD_TIMEOUT));
|
|
} else {
|
|
dev_dbg(&i2c->dev, "diseqc tx timeout\n");
|
|
|
|
ret = m88rs6060_update_bits(dev, 0xa1, 0xc0, 0x40);
|
|
if (ret)
|
|
goto err;
|
|
}
|
|
|
|
ret = m88rs6060_update_bits(dev, 0xa2, 0xc0, 0x80);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if (utmp == 1) {
|
|
ret = -ETIMEDOUT;
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
dev_dbg(&i2c->dev, "failed=%d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static int m88rs6060_diseqc_send_burst(struct dvb_frontend *fe,
|
|
enum fe_sec_mini_cmd fe_sec_mini_cmd)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret;
|
|
unsigned int utmp, burst;
|
|
unsigned long timeout;
|
|
|
|
dev_dbg(&i2c->dev, "fe_sec_mini_cmd=%d\n", fe_sec_mini_cmd);
|
|
|
|
if (!dev->warm) {
|
|
ret = -EAGAIN;
|
|
goto err;
|
|
}
|
|
|
|
utmp = dev->config.envelope_mode << 5;
|
|
ret = m88rs6060_update_bits(dev, 0xa2, 0xe0, utmp);
|
|
if (ret)
|
|
goto err;
|
|
|
|
switch (fe_sec_mini_cmd) {
|
|
case SEC_MINI_A:
|
|
burst = 0x02;
|
|
break;
|
|
case SEC_MINI_B:
|
|
burst = 0x01;
|
|
break;
|
|
default:
|
|
dev_dbg(&i2c->dev, "invalid fe_sec_mini_cmd\n");
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
|
|
ret = regmap_write(dev->regmap, 0xa1, burst);
|
|
if (ret)
|
|
goto err;
|
|
|
|
/* wait DiSEqC TX ready */
|
|
#define SEND_BURST_TIMEOUT 40
|
|
timeout = jiffies + msecs_to_jiffies(SEND_BURST_TIMEOUT);
|
|
|
|
/* DiSEqC ToneBurst period is 12.5 ms */
|
|
usleep_range(8500, 12500);
|
|
|
|
for (utmp = 1; !time_after(jiffies, timeout) && utmp;) {
|
|
ret = regmap_read(dev->regmap, 0xa1, &utmp);
|
|
if (ret)
|
|
goto err;
|
|
utmp = (utmp >> 6) & 0x1;
|
|
}
|
|
|
|
if (utmp == 0) {
|
|
dev_dbg(&i2c->dev, "diseqc tx took %u ms\n",
|
|
jiffies_to_msecs(jiffies) -
|
|
(jiffies_to_msecs(timeout) - SEND_BURST_TIMEOUT));
|
|
} else {
|
|
dev_dbg(&i2c->dev, "diseqc tx timeout\n");
|
|
|
|
ret = m88rs6060_update_bits(dev, 0xa1, 0xc0, 0x40);
|
|
if (ret)
|
|
goto err;
|
|
}
|
|
|
|
ret = m88rs6060_update_bits(dev, 0xa2, 0xc0, 0x80);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if (utmp == 1) {
|
|
ret = -ETIMEDOUT;
|
|
goto err;
|
|
}
|
|
|
|
return 0;
|
|
err:
|
|
dev_dbg(&i2c->dev, "failed=%d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static int m88rs6060_tune(struct dvb_frontend *fe, bool re_tune,
|
|
unsigned int mode_flags,
|
|
unsigned int *delay, enum fe_status *status)
|
|
{
|
|
//struct mxl *state = fe->demodulator_priv;
|
|
int r = 0;
|
|
|
|
*delay = HZ / 2;
|
|
if (re_tune) {
|
|
r = m88rs6060_set_frontend(fe);
|
|
if (r)
|
|
return r;
|
|
}
|
|
|
|
r = m88rs6060_read_status(fe, status);
|
|
if (r)
|
|
return r;
|
|
|
|
if (*status & FE_HAS_LOCK)
|
|
return 0;
|
|
|
|
return 0;
|
|
}
|
|
static int m88rs6060_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties *p)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
struct MT_FE_CHAN_INFO_DVBS2 p_info;
|
|
|
|
|
|
m88rs6060_get_channel_info(dev,&p_info);
|
|
|
|
switch(p_info.mod_mode)
|
|
{
|
|
case MtFeModMode_8psk:
|
|
p->modulation = PSK_8; break;
|
|
case MtFeModMode_16Apsk:
|
|
p->modulation = APSK_16; break;
|
|
case MtFeModMode_32Apsk:
|
|
p->modulation = APSK_32; break;
|
|
case MtFeModMode_64Apsk:
|
|
p->modulation = APSK_64; break;
|
|
case MtFeModMode_Qpsk:
|
|
default: p->modulation = QPSK; break;
|
|
}
|
|
switch(p_info.code_rate)
|
|
{
|
|
case MtFeCodeRate_1_4: p->fec_inner = FEC_1_4; break;
|
|
case MtFeCodeRate_1_3: p->fec_inner = FEC_1_3; break;
|
|
case MtFeCodeRate_2_5: p->fec_inner = FEC_2_5; break;
|
|
case MtFeCodeRate_1_2: p->fec_inner = FEC_1_2; break;
|
|
case MtFeCodeRate_3_5: p->fec_inner = FEC_3_5; break;
|
|
case MtFeCodeRate_2_3: p->fec_inner = FEC_2_3; break;
|
|
case MtFeCodeRate_3_4: p->fec_inner = FEC_3_4; break;
|
|
case MtFeCodeRate_4_5: p->fec_inner = FEC_4_5; break;
|
|
case MtFeCodeRate_5_6: p->fec_inner = FEC_5_6; break;
|
|
case MtFeCodeRate_7_8: p->fec_inner = FEC_7_8; break;
|
|
case MtFeCodeRate_8_9: p->fec_inner = FEC_8_9; break;
|
|
case MtFeCodeRate_9_10: p->fec_inner = FEC_9_10; break;
|
|
case MtFeCodeRate_5_9: p->fec_inner = FEC_5_9; break;
|
|
case MtFeCodeRate_7_9: p->fec_inner = FEC_7_9; break;
|
|
case MtFeCodeRate_4_15: p->fec_inner = FEC_4_15; break;
|
|
case MtFeCodeRate_7_15: p->fec_inner = FEC_7_15; break;
|
|
case MtFeCodeRate_8_15: p->fec_inner = FEC_8_15; break;
|
|
case MtFeCodeRate_11_15: p->fec_inner = FEC_11_15; break;
|
|
case MtFeCodeRate_13_18: p->fec_inner = FEC_13_18; break;
|
|
case MtFeCodeRate_9_20: p->fec_inner = FEC_9_20; break;
|
|
case MtFeCodeRate_11_20: p->fec_inner = FEC_11_20; break;
|
|
case MtFeCodeRate_23_36: p->fec_inner = FEC_23_36; break;
|
|
case MtFeCodeRate_25_36: p->fec_inner = FEC_25_36; break;
|
|
case MtFeCodeRate_11_45: p->fec_inner = FEC_11_45; break;
|
|
case MtFeCodeRate_13_45: p->fec_inner = FEC_13_45; break;
|
|
case MtFeCodeRate_14_45: p->fec_inner = FEC_14_45; break;
|
|
case MtFeCodeRate_26_45: p->fec_inner = FEC_26_45; break;
|
|
case MtFeCodeRate_28_45: p->fec_inner = FEC_28_45; break;
|
|
case MtFeCodeRate_29_45: p->fec_inner = FEC_29_45; break;
|
|
case MtFeCodeRate_31_45: p->fec_inner = FEC_31_45; break;
|
|
case MtFeCodeRate_32_45: p->fec_inner = FEC_32_45; break;
|
|
case MtFeCodeRate_77_90: p->fec_inner = FEC_77_90; break;
|
|
default: p->fec_inner = FEC_NONE; break;
|
|
}
|
|
p->pilot = p_info.is_pilot_on ? PILOT_ON : PILOT_OFF;
|
|
switch(p_info.roll_off){
|
|
case MtFeRollOff_0p35:
|
|
p->rolloff = ROLLOFF_35;break;
|
|
case MtFeRollOff_0p25:
|
|
p->rolloff = ROLLOFF_25;break;
|
|
case MtFeRollOff_0p20:
|
|
p->rolloff = ROLLOFF_20;break;
|
|
case MtFeRollOff_0p15:
|
|
p->rolloff = ROLLOFF_15;break;
|
|
case MtFeRollOff_0p10:
|
|
p->rolloff = ROLLOFF_10;break;
|
|
case MtFeRollOff_0p05:
|
|
p->rolloff = ROLLOFF_5;break;
|
|
default:
|
|
p->rolloff = ROLLOFF_AUTO;break;
|
|
}
|
|
p->inversion = (p_info.is_spectrum_inv -1) ?INVERSION_ON : INVERSION_OFF;
|
|
|
|
return 0;
|
|
}
|
|
static void m88rs6060_spi_read(struct dvb_frontend *fe,
|
|
struct ecp3_info *ecp3inf)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
|
|
if (dev->config.read_properties)
|
|
dev->config.read_properties(i2c, ecp3inf->reg,
|
|
&(ecp3inf->data));
|
|
|
|
return;
|
|
}
|
|
|
|
static void m88rs6060_spi_write(struct dvb_frontend *fe,
|
|
struct ecp3_info *ecp3inf)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
|
|
if (dev->config.write_properties)
|
|
dev->config.write_properties(i2c, ecp3inf->reg,
|
|
ecp3inf->data);
|
|
return;
|
|
}
|
|
|
|
static void m88rs6060_eeprom_read(struct dvb_frontend *fe, struct eeprom_info *eepinf)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
|
|
if (dev->config.read_eeprom)
|
|
dev->config.read_eeprom(i2c, eepinf->reg,
|
|
&(eepinf->data));
|
|
return ;
|
|
}
|
|
|
|
static void m88rs6060_eeprom_write(struct dvb_frontend *fe,struct eeprom_info *eepinf)
|
|
{
|
|
struct i2c_client *client = fe->demodulator_priv;
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
|
|
if (dev->config.write_eeprom)
|
|
dev->config.write_eeprom(i2c, eepinf->reg,
|
|
eepinf->data);
|
|
return ;
|
|
}
|
|
|
|
static const struct dvb_frontend_ops m88rs6060_ops = {
|
|
.delsys = {SYS_DVBS, SYS_DVBS2},
|
|
.info = {
|
|
.name = "Montage m88rs6060",
|
|
.frequency_min_hz = 950 * MHz,
|
|
.frequency_max_hz = 2150 * MHz,
|
|
.symbol_rate_min = 1000000,
|
|
.symbol_rate_max = 45000000,
|
|
.caps = FE_CAN_INVERSION_AUTO |
|
|
FE_CAN_FEC_AUTO |
|
|
FE_CAN_QPSK |
|
|
FE_CAN_RECOVER |
|
|
FE_CAN_2G_MODULATION |
|
|
FE_CAN_MULTISTREAM
|
|
},
|
|
|
|
.init = m88rs6060_init,
|
|
#ifdef HWTUNE
|
|
.get_frontend_algo = m88rs6060_get_algo,
|
|
.tune = m88rs6060_tune,
|
|
#else
|
|
.set_frontend = m88rs6060_set_frontend,
|
|
#endif
|
|
.get_frontend = m88rs6060_get_frontend,
|
|
.read_status = m88rs6060_read_status,
|
|
.read_ber = m88rs6060_read_ber,
|
|
.read_signal_strength = m88rs6060_read_signal_strength,
|
|
.read_snr = m88rs6060_read_snr,
|
|
.set_voltage = m88rs6060_set_voltage,
|
|
.set_tone = m88rs6060_set_tone,
|
|
.diseqc_send_burst = m88rs6060_diseqc_send_burst,
|
|
.diseqc_send_master_cmd = m88rs6060_diseqc_send_master_cmd,
|
|
.spi_read = m88rs6060_spi_read,
|
|
.spi_write = m88rs6060_spi_write,
|
|
.eeprom_read = m88rs6060_eeprom_read,
|
|
.eeprom_write = m88rs6060_eeprom_write,
|
|
|
|
};
|
|
static int m88rs6060_ready(struct m88rs6060_dev *dev)
|
|
{
|
|
//struct m88rs6060_dev *dev= i2c_get_clientdata(client);
|
|
struct i2c_adapter *i2c = dev->base->i2c;
|
|
int ret, len, rem;
|
|
const struct firmware *firmware;
|
|
const char *name = M88RS6060_FIRMWARE;
|
|
unsigned val;
|
|
|
|
dev_dbg(&dev->base->i2c->dev, "%s", __func__);
|
|
|
|
//rest the harware and wake up the demod and tuner;
|
|
m88rs6060_hard_rest(dev);
|
|
rs6060_init(dev);
|
|
|
|
ret = regmap_write(dev->regmap, 0x07, 0xe0); //global reset ,diseqc and fec reset
|
|
if (ret)
|
|
goto err;
|
|
ret = regmap_write(dev->regmap, 0x07, 0x00);
|
|
if (ret)
|
|
goto err;
|
|
|
|
/* cold state - try to download firmware */
|
|
dev_info(&i2c->dev, "found a '%s' in cold state\n",
|
|
dev->fe.ops.info.name);
|
|
|
|
/* request the firmware, this will block and timeout */
|
|
ret = request_firmware(&firmware, name, &i2c->dev);
|
|
if (ret) {
|
|
dev_err(&i2c->dev, "firmware file '%s' not found\n", name);
|
|
goto err;
|
|
}
|
|
|
|
dev_info(&i2c->dev, "downloading firmware from file '%s'\n", name);
|
|
|
|
ret = regmap_write(dev->regmap, 0xb2, 0x01);
|
|
if (ret)
|
|
goto err_release_firmware;
|
|
|
|
dev_dbg(&i2c->dev, " firmware size = %lu data %02x %02x %02x\n",
|
|
firmware->size, firmware->data[0], firmware->data[1],
|
|
firmware->data[2]);
|
|
|
|
for (rem = firmware->size; rem > 0; rem -= (dev->config.i2c_wr_max - 1)) {
|
|
len = min(dev->config.i2c_wr_max - 1, rem);
|
|
ret = m88rs6060_fireware_download(dev, 0xb0,
|
|
&firmware->data[firmware->size - rem],
|
|
len);
|
|
if (ret) {
|
|
dev_err(&i2c->dev,
|
|
"firmware download failed len %d %d\n", len,
|
|
ret);
|
|
goto err_release_firmware;
|
|
}
|
|
}
|
|
|
|
ret = regmap_write(dev->regmap, 0xb2, 0x00);
|
|
if (ret)
|
|
goto err_release_firmware;
|
|
|
|
release_firmware(firmware);
|
|
|
|
ret = regmap_read(dev->regmap, 0xb9, &val);
|
|
if (ret)
|
|
goto err;
|
|
|
|
if (!val) {
|
|
ret = -EINVAL;
|
|
dev_info(&i2c->dev, "firmware did not run\n");
|
|
goto err;
|
|
}
|
|
|
|
dev_info(&i2c->dev, "found a '%s' in warm state\n",
|
|
dev->fe.ops.info.name);
|
|
dev_info(&i2c->dev, "firmware version:%X\n", val);
|
|
msleep(5);
|
|
m88res6060_set_ts_mode(dev);
|
|
|
|
regmap_read(dev->regmap, 0x4d, &val);
|
|
regmap_write(dev->regmap, 0x4d, val & 0xfd);
|
|
|
|
return 0;
|
|
err_release_firmware:
|
|
release_firmware(firmware);
|
|
err:
|
|
dev_dbg(&i2c->dev, "failed=%d\n", ret);
|
|
return ret;
|
|
|
|
}
|
|
static struct m88rs6060_base*match_base(struct i2c_adapter*i2c,u8 adr)
|
|
{
|
|
struct m88rs6060_base*p;
|
|
|
|
list_for_each_entry(p,&m88rs6060list,m88rs6060list)
|
|
if(p->i2c == i2c) // for two adapter in same i2c.
|
|
return p;
|
|
return NULL;
|
|
}
|
|
static struct si5351_base*match_si5351_base(struct i2c_adapter*i2c,int clk_port)
|
|
{
|
|
struct si5351_base*p;
|
|
|
|
list_for_each_entry(p,&si5351list,si5351list)
|
|
if((p->i2c_si5351!= i2c)&&(p->clk_port!=clk_port))// for 6910v12 just a si5351 control two CI
|
|
return p;
|
|
return NULL;
|
|
|
|
}
|
|
static int m88rs6060_probe(struct i2c_client *client)
|
|
{
|
|
struct m88rs6060_cfg *cfg = client->dev.platform_data;
|
|
struct m88rs6060_dev *dev;
|
|
struct m88rs6060_base *base;
|
|
int ret;
|
|
unsigned tmp;
|
|
static const struct regmap_config regmap_config = {
|
|
.reg_bits = 8,
|
|
.val_bits = 8,
|
|
};
|
|
|
|
dev_dbg(&client->dev, "\n");
|
|
|
|
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
|
if (!dev) {
|
|
ret = -ENOMEM;
|
|
goto err_kfree;
|
|
}
|
|
|
|
dev->config.demod_adr = cfg->demod_adr;
|
|
dev->config.tuner_adr = cfg->tuner_adr;
|
|
dev->config.clk = cfg->clk;
|
|
dev->config.ts_mode = cfg->ts_mode;
|
|
dev->config.i2c_wr_max = cfg->i2c_wr_max;
|
|
dev->config.ts_pinswitch = cfg->ts_pinswitch;
|
|
dev->config.ts_autoclock = cfg->ts_autoclock;
|
|
dev->config.repeater_value = cfg->repeater_value;
|
|
dev->config.read_properties = cfg->read_properties;
|
|
dev->config.write_properties = cfg->write_properties;
|
|
dev->config.read_eeprom = cfg->read_eeprom;
|
|
dev->config.write_eeprom = cfg->write_eeprom;
|
|
dev->config.RF_switch = cfg->RF_switch;
|
|
dev->config.TS_switch = cfg->TS_switch;
|
|
dev->config.LED_switch = cfg->LED_switch;
|
|
dev->config.envelope_mode = cfg->envelope_mode;
|
|
dev->config.disable_22k = cfg->disable_22k;
|
|
dev->TsClockChecked = false;
|
|
dev->config.SetCIClock= cfg->SetCIClock;
|
|
dev->config.SetTimes= cfg->SetTimes;
|
|
dev->config.HAS_CI = cfg->HAS_CI;
|
|
dev->config.num = cfg->num;
|
|
dev->newTP = 0;
|
|
|
|
|
|
//for i2c
|
|
base = match_base(client->adapter,client->addr);
|
|
if(base){
|
|
base->count++;
|
|
dev->base = base;
|
|
}else{
|
|
base = kzalloc(sizeof(struct m88rs6060_base),GFP_KERNEL);
|
|
if(!base)
|
|
goto err_kfree;
|
|
base->i2c = client->adapter;
|
|
base->count = 1;
|
|
base->adr = client->addr;
|
|
mutex_init(&base->i2c_mutex);
|
|
list_add(&base->m88rs6060list,&m88rs6060list);
|
|
dev->base= base;
|
|
}
|
|
|
|
dev->regmap = regmap_init_i2c(client, ®map_config);
|
|
if (IS_ERR(dev->regmap)) {
|
|
ret = PTR_ERR(dev->regmap);
|
|
goto err_base_kfree;
|
|
}
|
|
/*check demod i2c */
|
|
ret = regmap_read(dev->regmap, 0x00, &tmp);
|
|
if (ret)
|
|
goto err_regmap_exit;
|
|
if (tmp != 0xe2)
|
|
{
|
|
ret = -ENODEV;
|
|
goto err_regmap_exit;
|
|
}
|
|
|
|
dev->mclk = 96000;
|
|
|
|
memcpy(&dev->fe.ops, &m88rs6060_ops, sizeof(struct dvb_frontend_ops));
|
|
*cfg->fe = &dev->fe;
|
|
dev->fe_status = 0;
|
|
|
|
if(dev->config.HAS_CI){ //for 6910SECI
|
|
//for ci clk si5351
|
|
struct si5351_priv *priv;
|
|
struct si5351_base *base1;
|
|
|
|
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
|
|
if (!priv) {
|
|
ret = -ENOMEM;
|
|
}
|
|
base1 = match_si5351_base(client->adapter,cfg->clk_port);
|
|
if(base1){
|
|
base1->count++;
|
|
priv->base1 = base1;
|
|
|
|
}else{
|
|
|
|
base1 = kzalloc(sizeof(struct si5351_base),GFP_KERNEL);
|
|
if(!base1)
|
|
goto err_regmap_exit;
|
|
base1->i2c_si5351= client->adapter;
|
|
base1->count = 1;
|
|
base1->clk_port = cfg->clk_port;
|
|
mutex_init(&base1->i2c_mutex_ci);
|
|
list_add(&base1->si5351list,&si5351list);
|
|
priv->base1 = base1;
|
|
}
|
|
priv->clk_port = cfg->clk_port;
|
|
priv->plla_freq = 0;
|
|
priv->pllb_freq = 0;
|
|
dev->priv = priv;
|
|
|
|
if(cfg->clk_port==0){
|
|
si5351_init(priv);
|
|
si5351_clock_enable(priv,SI5351_CLK0,1);
|
|
si5351_clock_enable(priv,SI5351_CLK1,1);
|
|
si5351_set_freq(priv,41666666,0,SI5351_CLK0);
|
|
si5351_set_freq(priv,41666666,0,SI5351_CLK1);
|
|
}
|
|
}
|
|
|
|
dev->fe.demodulator_priv = client;
|
|
i2c_set_clientdata(client, dev);
|
|
|
|
/* set cold state */
|
|
dev->warm = false;
|
|
|
|
dev_dbg(&client->dev, "found the chip of %s.", m88rs6060_ops.info.name);
|
|
//ready chip
|
|
m88rs6060_ready(dev);
|
|
|
|
return 0;
|
|
|
|
err_regmap_exit:
|
|
regmap_exit(dev->regmap);
|
|
err_base_kfree:
|
|
base->count--;
|
|
if (base->count==0) {
|
|
list_del(&base->m88rs6060list);
|
|
kfree(base);
|
|
}
|
|
err_kfree:
|
|
kfree(dev);
|
|
|
|
dev_warn(&client->dev, "probe failed = %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
static void m88rs6060_remove(struct i2c_client *client)
|
|
{
|
|
struct m88rs6060_dev *dev = i2c_get_clientdata(client);
|
|
|
|
dev_dbg(&client->dev, "\n");
|
|
|
|
dev->base->count --;
|
|
if(dev->base->count==0)
|
|
{
|
|
list_del(&dev->base->m88rs6060list);
|
|
kfree(dev->base);
|
|
}
|
|
if(dev->priv){
|
|
dev->priv->base1->count --;
|
|
if(dev->priv->base1->count==0){
|
|
list_del(&dev->priv->base1->si5351list);
|
|
kfree(dev->priv);
|
|
}
|
|
}
|
|
regmap_exit(dev->regmap);
|
|
dev->fe.ops.release = NULL;
|
|
dev->fe.demodulator_priv = NULL;
|
|
|
|
kfree(dev);
|
|
}
|
|
|
|
static const struct i2c_device_id m88rs6060_id_table[] = {
|
|
{"m88rs6060", 0},
|
|
{}
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, m88rs6060_id_table);
|
|
|
|
static struct i2c_driver m88rs6060_driver = {
|
|
.driver = {
|
|
.name = "m88rs6060",
|
|
},
|
|
.probe = m88rs6060_probe,
|
|
.remove = m88rs6060_remove,
|
|
.id_table = m88rs6060_id_table,
|
|
};
|
|
|
|
module_i2c_driver(m88rs6060_driver);
|
|
|
|
MODULE_AUTHOR("Davin zhang <Davin@tbsdtv.com>");
|
|
MODULE_DESCRIPTION("Montage M88RS6060 driver");
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_FIRMWARE(M88RS6060_FIRMWARE);
|