Commit 48937295 authored by Steven Toth's avatar Steven Toth Committed by Mauro Carvalho Chehab

V4L/DVB(7871): mxl5005s: Re-org code and update copyrights

Re-org code and update copyrights
Signed-off-by: default avatarSteven Toth <stoth@hauppauge.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 5c1b2051
/*
* For the Realtek RTL chip RTL2831U
* Realtek Release Date: 2008-03-14, ver 080314
* Realtek version RTL2831 Linux driver version 080314
* ver 080314
*
* for linux kernel version 2.6.21.4 - 2.6.22-14
* support MXL5005s and MT2060 tuners (support tuner auto-detecting)
* support two IR types -- RC5 and NEC
*
* Known boards with Realtek RTL chip RTL2821U
* Freecom USB stick 14aa:0160 (version 4)
* Conceptronic CTVDIGRCU
*
* Copyright (c) 2008 Realtek
* Copyright (c) 2008 Jan Hoogenraad, Barnaby Shearer, Andy Hasper
* This code is placed under the terms of the GNU General Public License
*
* Released by Realtek under GPLv2.
* Thanks to Realtek for a lot of support we received !
*
* Revision: 080314 - original version
*/
MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
Copyright (C) 2008 MaxLinear
Copyright (C) 2006 Steven Toth <stoth@hauppauge.com>
Functions:
mxl5005s_reset()
mxl5005s_writereg()
mxl5005s_writeregs()
mxl5005s_init()
mxl5005s_reconfigure()
mxl5005s_AssignTunerMode()
mxl5005s_set_params()
mxl5005s_get_frequency()
mxl5005s_get_bandwidth()
mxl5005s_release()
mxl5005s_attach()
Copyright (c) 2008 Realtek
Copyright (c) 2008 Jan Hoogenraad, Barnaby Shearer, Andy Hasper
Functions:
mxl5005s_SetRfFreqHz()
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
History of this driver (Steven Toth):
I was given a public release of a linux driver that included
support for the MaxLinear MXL5005S silicon tuner. Analysis of
the tuner driver showed clearly three things.
1. The tuner driver didn't support the LinuxTV tuner API
so the code Realtek added had to be removed.
2. A significant amount of the driver is reference driver code
from MaxLinear, I felt it was important to identify and
preserve this.
3. New code has to be added to interface correctly with the
LinuxTV API, as a regular kernel module.
Other than the reference driver enum's, I've clearly marked
sections of the code and retained the copyright of the
respective owners.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
......@@ -31,10 +66,10 @@
#include "dvb_frontend.h"
#include "mxl5005s.h"
static int debug;
static int debug = 2;
#define dprintk(level, arg...) do { \
if (debug >= level) \
if (level <= debug) \
printk(arg); \
} while (0)
......@@ -50,13 +85,6 @@ static int debug;
#define MXLCTRL_NUM 189
#define MASTER_CONTROL_ADDR 9
/* Enumeration of AGC Mode */
typedef enum
{
MXL_DUAL_AGC = 0,
MXL_SINGLE_AGC
} AGC_Mode;
/* Enumeration of Master Control Register State */
typedef enum
{
......@@ -66,51 +94,6 @@ typedef enum
MC_SEQ_OFF
} Master_Control_State;
/* Enumeration of MXL5005 Tuner Mode */
typedef enum
{
MXL_ANALOG_MODE = 0,
MXL_DIGITAL_MODE
} Tuner_Mode;
/* Enumeration of MXL5005 Tuner IF Mode */
typedef enum
{
MXL_ZERO_IF = 0,
MXL_LOW_IF
} Tuner_IF_Mode;
/* Enumeration of MXL5005 Tuner Clock Out Mode */
typedef enum
{
MXL_CLOCK_OUT_DISABLE = 0,
MXL_CLOCK_OUT_ENABLE
} Tuner_Clock_Out;
/* Enumeration of MXL5005 Tuner Div Out Mode */
typedef enum
{
MXL_DIV_OUT_1 = 0,
MXL_DIV_OUT_4
} Tuner_Div_Out;
/* Enumeration of MXL5005 Tuner Pull-up Cap Select Mode */
typedef enum
{
MXL_CAP_SEL_DISABLE = 0,
MXL_CAP_SEL_ENABLE
} Tuner_Cap_Select;
/* Enumeration of MXL5005 Tuner RSSI Mode */
typedef enum
{
MXL_RSSI_DISABLE = 0,
MXL_RSSI_ENABLE
} Tuner_RSSI;
/* Enumeration of MXL5005 Tuner Modulation Type */
typedef enum
{
......@@ -122,22 +105,6 @@ typedef enum
MXL_ANALOG_OTA
} Tuner_Modu_Type;
/* Enumeration of MXL5005 Tuner Tracking Filter Type */
typedef enum
{
MXL_TF_DEFAULT = 0,
MXL_TF_OFF,
MXL_TF_C,
MXL_TF_C_H,
MXL_TF_D,
MXL_TF_D_L,
MXL_TF_E,
MXL_TF_F,
MXL_TF_E_2,
MXL_TF_E_NA,
MXL_TF_G
} Tuner_TF_Type;
/* MXL5005 Tuner Register Struct */
typedef struct _TunerReg_struct
{
......@@ -268,33 +235,6 @@ enum
};
#define MXL5005S_BANDWIDTH_MODE_NUM 3
/* Top modes */
enum
{
MXL5005S_TOP_5P5 = 55,
MXL5005S_TOP_7P2 = 72,
MXL5005S_TOP_9P2 = 92,
MXL5005S_TOP_11P0 = 110,
MXL5005S_TOP_12P9 = 129,
MXL5005S_TOP_14P7 = 147,
MXL5005S_TOP_16P8 = 168,
MXL5005S_TOP_19P4 = 194,
MXL5005S_TOP_21P2 = 212,
MXL5005S_TOP_23P2 = 232,
MXL5005S_TOP_25P2 = 252,
MXL5005S_TOP_27P1 = 271,
MXL5005S_TOP_29P2 = 292,
MXL5005S_TOP_31P7 = 317,
MXL5005S_TOP_34P9 = 349,
};
/* IF output load */
enum
{
MXL5005S_IF_OUTPUT_LOAD_200_OHM = 200,
MXL5005S_IF_OUTPUT_LOAD_300_OHM = 300,
};
/* MXL5005 Tuner Control Struct */
typedef struct _TunerControl_struct {
u16 Ctrl_Num; /* Control Number */
......@@ -349,13 +289,15 @@ struct mxl5005s_state
TunerRegs[TUNER_REGS_NUM]; /* Tuner Register Array Pointer */
/* Linux driver framework specific */
const struct mxl5005s_config *config;
struct mxl5005s_config *config;
struct dvb_frontend *frontend;
struct i2c_adapter *i2c;
/* Cache values */
u32 current_mode;
};
// funcs
u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value);
u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value);
u16 MXL_GetMasterControl(u8 *MasterReg, int state);
......@@ -372,14 +314,26 @@ u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq);
void MXL_SynthIFLO_Calc(struct dvb_frontend *fe);
void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe);
u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 *RegNum, u8 *RegVal, int *count);
int mxl5005s_SetRegsWithTable(struct dvb_frontend *fe, u8 *pAddrTable, u8 *pByteTable, int TableLen);
int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, u8 *datatable, u8 len);
u16 MXL_IFSynthInit(struct dvb_frontend *fe);
static int mxl5005s_init2(struct dvb_frontend *fe);
int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, u32 bandwidth);
int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, u32 bandwidth);
/* ----------------------------------------------------------------
* Begin: Custom code salvaged from the Realtek driver.
* Copyright (c) 2008 Realtek
* Copyright (c) 2008 Jan Hoogenraad, Barnaby Shearer, Andy Hasper
* This code is placed under the terms of the GNU General Public License
*
* Released by Realtek under GPLv2.
* Thanks to Realtek for a lot of support we received !
*
* Revision: 080314 - original version
*/
int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
{
struct mxl5005s_state *state = fe->tuner_priv;
u8 AgcMasterByte = state->config->AgcMasterByte;
unsigned char AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
unsigned char ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
int TableLen;
......@@ -396,7 +350,7 @@ int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
AddrTable[0] = MASTER_CONTROL_ADDR;
ByteTable[0] |= state->config->AgcMasterByte;
mxl5005s_SetRegsWithTable(fe, AddrTable, ByteTable, 1);
mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
// Tuner RF frequency setting stage 1
MXL_TuneRF(fe, RfFreqHz);
......@@ -410,13 +364,13 @@ int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START) ;
AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
ByteTable[TableLen] = MasterControlByte | AgcMasterByte;
ByteTable[TableLen] = MasterControlByte | state->config->AgcMasterByte;
TableLen += 1;
mxl5005s_SetRegsWithTable(fe, AddrTable, ByteTable, TableLen);
mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
// Wait 30 ms.
msleep(30);
msleep(150);
// Tuner RF frequency setting stage 2
MXL_ControlWrite(fe, SEQ_FSM_PULSE, 1) ;
......@@ -425,101 +379,21 @@ int mxl5005s_SetRfFreqHz(struct dvb_frontend *fe, unsigned long RfFreqHz)
MXL_GetMasterControl(&MasterControlByte, MC_LOAD_START) ;
AddrTable[TableLen] = MASTER_CONTROL_ADDR ;
ByteTable[TableLen] = MasterControlByte | AgcMasterByte ;
ByteTable[TableLen] = MasterControlByte | state->config->AgcMasterByte ;
TableLen += 1;
mxl5005s_SetRegsWithTable(fe, AddrTable, ByteTable, TableLen);
mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
return 0;
}
msleep(100);
/* Write a single byte to a single reg */
static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val)
{
struct mxl5005s_state *state = fe->tuner_priv;
u8 buf[2] = { reg, val };
struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
.buf = buf, .len = 2 };
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
printk(KERN_WARNING "mxl5005s I2C write failed\n");
return -EREMOTEIO;
}
return 0;
}
/* End: Custom code taken from the Realtek driver */
/* Write a word to a single reg */
static int mxl5005s_writereg16(struct dvb_frontend *fe, u8 reg, u16 val)
{
struct mxl5005s_state *state = fe->tuner_priv;
u8 buf[3] = { reg, val >> 8 , val & 0xff };
struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
.buf = buf, .len = 3 };
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
printk(KERN_WARNING "mxl5005s I2C write16 failed\n");
return -EREMOTEIO;
}
return 0;
}
int mxl5005s_SetRegsWithTable(struct dvb_frontend *fe, u8 *pAddrTable, u8 *pByteTable, int TableLen)
{
int i, ret;
u8 end_two_bytes_buf[]={ 0 , 0 };
for( i = 0 ; i < TableLen - 1 ; i++)
{
ret = mxl5005s_writereg(fe, pAddrTable[i], pByteTable[i]);
if (!ret)
return ret;
}
end_two_bytes_buf[0] = pByteTable[i];
end_two_bytes_buf[1] = MXL5005S_LATCH_BYTE;
ret = mxl5005s_writereg16(fe, pAddrTable[i], (end_two_bytes_buf[0] << 8) | end_two_bytes_buf[1]);
return ret;
}
int mxl5005s_SetRegMaskBits(struct dvb_frontend *fe,
unsigned char RegAddr,
unsigned char Msb,
unsigned char Lsb,
const unsigned char WritingValue
)
{
int i;
unsigned char Mask;
unsigned char Shift;
unsigned char RegByte;
/* Generate mask and shift according to MSB and LSB. */
Mask = 0;
for(i = Lsb; i < (unsigned char)(Msb + 1); i++)
Mask |= 0x1 << i;
Shift = Lsb;
/* Get tuner register byte according to register adddress. */
MXL_RegRead(fe, RegAddr, &RegByte);
/* Reserve register byte unmask bit with mask and inlay writing value into it. */
RegByte &= ~Mask;
RegByte |= (WritingValue << Shift) & Mask;
/* Update tuner register byte table. */
MXL_RegWrite(fe, RegAddr, RegByte);
/* Write tuner register byte with writing byte. */
return mxl5005s_SetRegsWithTable(fe, &RegAddr, &RegByte, 1);
}
// The following context is source code provided by MaxLinear.
// MaxLinear source code - MXL5005_Initialize.cpp
// DONE
/* ----------------------------------------------------------------
* Begin: Reference driver code found in the Realtek driver.
* Copyright (c) 2008 MaxLinear
*/
u16 MXL5005_RegisterInit(struct dvb_frontend *fe)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -841,7 +715,6 @@ u16 MXL5005_RegisterInit(struct dvb_frontend *fe)
return 0 ;
}
// DONE
u16 MXL5005_ControlInit(struct dvb_frontend *fe)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -1785,7 +1658,6 @@ u16 MXL5005_ControlInit(struct dvb_frontend *fe)
// MaxLinear source code - MXL5005_c.cpp
// MXL5005.cpp : Defines the initialization routines for the DLL.
// 2.6.12
// DONE
void InitTunerControls(struct dvb_frontend *fe)
{
MXL5005_RegisterInit(fe);
......@@ -1828,7 +1700,6 @@ void InitTunerControls(struct dvb_frontend *fe)
// > 0 : Failed //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
u8 Mode, /* 0: Analog Mode ; 1: Digital Mode */
u8 IF_mode, /* for Analog Mode, 0: zero IF; 1: low IF */
......@@ -1898,7 +1769,6 @@ u16 MXL5005_TunerConfig(struct dvb_frontend *fe,
// > 0 : Failed //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -1937,7 +1807,6 @@ void MXL_SynthIFLO_Calc(struct dvb_frontend *fe)
// > 0 : Failed //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -1976,7 +1845,6 @@ void MXL_SynthRFTGLO_Calc(struct dvb_frontend *fe)
// > 0 : Failed //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_OverwriteICDefault(struct dvb_frontend *fe)
{
u16 status = 0;
......@@ -2014,7 +1882,6 @@ u16 MXL_OverwriteICDefault(struct dvb_frontend *fe)
// > 0 : Failed //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_BlockInit(struct dvb_frontend *fe)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -2042,6 +1909,7 @@ u16 MXL_BlockInit(struct dvb_frontend *fe)
status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 2);
break;
case 6000000:
printk("%s() doing 6MHz digital\n", __func__);
status += MXL_ControlWrite(fe, BB_DLPF_BANDSEL, 3);
break;
}
......@@ -2072,7 +1940,6 @@ u16 MXL_BlockInit(struct dvb_frontend *fe)
else /* Single AGC Mode Dig Ana */
status += MXL_ControlWrite(fe, AGC_RF, state->Mode ? 15 : 12);
if (state->TOP == 55) /* TOP == 5.5 */
status += MXL_ControlWrite(fe, AGC_IF, 0x0);
......@@ -2302,6 +2169,8 @@ u16 MXL_BlockInit(struct dvb_frontend *fe)
status += MXL_ControlWrite(fe, BB_IQSWAP, 0);
else /* High IF */
status += MXL_ControlWrite(fe, BB_IQSWAP, 1);
status += MXL_ControlWrite(fe, RFSYN_CHP_GAIN, 2);
}
if (state->Mod_Type == MXL_ANALOG_CABLE) {
/* Analog Cable Mode */
......@@ -2338,7 +2207,7 @@ u16 MXL_BlockInit(struct dvb_frontend *fe)
}
/* RSSI disable */
if(state->EN_RSSI==0) {
if(state->EN_RSSI == 0) {
status += MXL_ControlWrite(fe, SEQ_EXTSYNTHCALIF, 1);
status += MXL_ControlWrite(fe, SEQ_EXTDCCAL, 1);
status += MXL_ControlWrite(fe, AGC_EN_RSSI, 0);
......@@ -2547,6 +2416,7 @@ u16 MXL_IFSynthInit(struct dvb_frontend *fe)
Fref = 324000000UL ;
}
if (state->IF_LO == 5380000UL) {
printk("%s() doing 5.38\n", __func__);
status += MXL_ControlWrite(fe, IF_DIVVAL, 0x07) ;
status += MXL_ControlWrite(fe, IF_VCO_BIAS, 0x0C) ;
Fref = 322800000UL ;
......@@ -3229,6 +3099,7 @@ u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
if (state->TF_Type == MXL_TF_C_H) // Tracking Filter type C-H for Hauppauge only
{
printk("%s() CH filter\n", __func__);
status += MXL_ControlWrite(fe, DAC_DIN_A, 0) ;
if (state->RF_IN >= 43000000 && state->RF_IN < 150000000)
......@@ -3767,7 +3638,6 @@ u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
return status ;
}
// DONE
u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val)
{
u16 status = 0;
......@@ -3834,7 +3704,6 @@ u16 MXL_SetGPIO(struct dvb_frontend *fe, u8 GPIO_Num, u8 GPIO_Val)
// >0 : Value exceed maximum allowed for control number //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value)
{
u16 status = 0;
......@@ -3875,7 +3744,6 @@ u16 MXL_ControlWrite(struct dvb_frontend *fe, u16 ControlNum, u32 value)
// 2 : Control name not found //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, u32 value, u16 controlGroup)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -3982,7 +3850,6 @@ u16 MXL_ControlWrite_Group(struct dvb_frontend *fe, u16 controlNum, u32 value, u
// -1 : Invalid Register Address //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_RegWrite(struct dvb_frontend *fe, u8 RegNum, u8 RegVal)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -4022,7 +3889,6 @@ u16 MXL_RegWrite(struct dvb_frontend *fe, u8 RegNum, u8 RegVal)
// -1 : Invalid Register Address //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -4059,7 +3925,6 @@ u16 MXL_RegRead(struct dvb_frontend *fe, u8 RegNum, u8 *RegVal)
// -1 : Invalid control name //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -4131,7 +3996,6 @@ u16 MXL_ControlRead(struct dvb_frontend *fe, u16 controlNum, u32 *value)
// -1 : Invalid control name //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u16 MXL_ControlRegRead(struct dvb_frontend *fe, u16 controlNum, u8 *RegNum, int * count)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -4237,7 +4101,6 @@ u16 MXL_ControlRegRead(struct dvb_frontend *fe, u16 controlNum, u8 *RegNum, int
// NONE //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, u8 bitVal)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -4285,7 +4148,6 @@ void MXL_RegWriteBit(struct dvb_frontend *fe, u8 address, u8 bit, u8 bitVal)
// Computed value //
// //
///////////////////////////////////////////////////////////////////////////////
// DONE
u32 MXL_Ceiling(u32 value, u32 resolution)
{
return (value/resolution + (value % resolution > 0 ? 1 : 0));
......@@ -4294,7 +4156,6 @@ u32 MXL_Ceiling(u32 value, u32 resolution)
//
// Retrieve the Initialzation Registers
//
// DONE
u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, int *count)
{
u16 status = 0;
......@@ -4317,7 +4178,6 @@ u16 MXL_GetInitRegister(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, int *c
return status;
}
// DONE
u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, int *count)
{
u16 status = 0;
......@@ -4345,7 +4205,6 @@ u16 MXL_GetCHRegister(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, int *cou
return status;
}
// DONE
u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, int *count)
{
u16 status = 0;
......@@ -4363,7 +4222,6 @@ u16 MXL_GetCHRegister_ZeroIF(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, i
return status;
}
// DONE
u16 MXL_GetCHRegister_LowIF(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, int *count)
{
u16 status = 0;
......@@ -4381,7 +4239,6 @@ u16 MXL_GetCHRegister_LowIF(struct dvb_frontend *fe, u8 * RegNum, u8 *RegVal, in
return status;
}
// DONE
u16 MXL_GetMasterControl(u8 *MasterReg, int state)
{
if (state == 1) /* Load_Start */
......@@ -4526,7 +4383,6 @@ u16 MXL_VCORange_Test(struct dvb_frontend *fe, int VCO_Range)
return status;
}
// DONE
u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
{
struct mxl5005s_state *state = fe->tuner_priv;
......@@ -4537,141 +4393,224 @@ u16 MXL_Hystersis_Test(struct dvb_frontend *fe, int Hystersis)
return status;
}
#endif
/* End: Reference driver code found in the Realtek driver that
* is copyright MaxLinear */
/* Linux driver related functions */
int mxl5005s_init(struct dvb_frontend *fe)
/* ----------------------------------------------------------------
* Begin: Everything after here is new code to adapt the
* proprietary Realtek driver into a Linux API tuner.
* Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
*/
static int mxl5005s_reset(struct dvb_frontend *fe)
{
int MxlModMode;
int MxlIfMode;
unsigned long MxlBandwitdh;
unsigned long MxlIfFreqHz;
unsigned long MxlCrystalFreqHz;
int MxlAgcMode;
unsigned short MxlTop;
unsigned short MxlIfOutputLoad;
int MxlClockOut;
int MxlDivOut;
int MxlCapSel;
int MxlRssiOnOff;
unsigned char MxlStandard;
unsigned char MxlTfType;
struct mxl5005s_state *state = fe->tuner_priv;
int ret = 0;
/* Set MxL5005S parameters. */
MxlModMode = MXL_DIGITAL_MODE;
MxlIfMode = MXL_ZERO_IF;
// steve
//MxlBandwitdh = MXL5005S_BANDWIDTH_8MHZ;
//MxlIfFreqHz = IF_FREQ_4570000HZ;
MxlBandwitdh = MXL5005S_BANDWIDTH_6MHZ; // config
MxlIfFreqHz = IF_FREQ_5380000HZ; // config
MxlCrystalFreqHz = CRYSTAL_FREQ_16000000HZ; // config
MxlAgcMode = MXL_SINGLE_AGC;
MxlTop = MXL5005S_TOP_25P2;
MxlIfOutputLoad = MXL5005S_IF_OUTPUT_LOAD_200_OHM;
MxlClockOut = MXL_CLOCK_OUT_DISABLE;
MxlDivOut = MXL_DIV_OUT_4;
MxlCapSel = MXL_CAP_SEL_ENABLE;
MxlRssiOnOff = MXL_RSSI_ENABLE; // config
MxlTfType = MXL_TF_C_H; // config
MxlStandard = MXL_ATSC; // config
// TODO: this is bad, it trashes other configs
// Set MxL5005S extra module.
//pExtra->AgcMasterByte = (MxlAgcMode == MXL_DUAL_AGC) ? 0x4 : 0x0;
u8 buf[2] = { 0xff, 0x00 };
struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
.buf = buf, .len = 2 };
MXL5005_TunerConfig(
fe,
(unsigned char)MxlModMode,
(unsigned char)MxlIfMode,
MxlBandwitdh,
MxlIfFreqHz,
MxlCrystalFreqHz,
(unsigned char)MxlAgcMode,
MxlTop,
MxlIfOutputLoad,
(unsigned char)MxlClockOut,
(unsigned char)MxlDivOut,
(unsigned char)MxlCapSel,
(unsigned char)MxlRssiOnOff,
MxlStandard, MxlTfType);
return mxl5005s_init2(fe);
}
dprintk(2, "%s()\n", __func__);
static int mxl5005s_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
u32 freq;
u32 bw;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if (fe->ops.info.type == FE_OFDM)
bw = params->u.ofdm.bandwidth;
else
bw = MXL5005S_BANDWIDTH_6MHZ;
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
printk(KERN_WARNING "mxl5005s I2C reset failed\n");
ret = -EREMOTEIO;
}
freq = params->frequency; /* Hz */
dprintk(1, "%s() freq=%d bw=%d\n", __func__, freq, bw);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
return mxl5005s_SetRfFreqHz(fe, freq);
return ret;
}
static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency)
/* Write a single byte to a single reg, latch the value if required by
* following the transaction with the latch byte.
*/
static int mxl5005s_writereg(struct dvb_frontend *fe, u8 reg, u8 val, int latch)
{
struct mxl5005s_state *state = fe->tuner_priv;
dprintk(1, "%s()\n", __func__);
u8 buf[3] = { reg, val, MXL5005S_LATCH_BYTE };
struct i2c_msg msg = { .addr = state->config->i2c_address, .flags = 0,
.buf = buf, .len = 3 };
*frequency = state->RF_IN;
if (latch == 0)
msg.len = 2;
dprintk(2, "%s(reg = 0x%x val = 0x%x addr = 0x%x)\n", __func__, reg, val, msg.addr);
if (i2c_transfer(state->i2c, &msg, 1) != 1) {
printk(KERN_WARNING "mxl5005s I2C write failed\n");
return -EREMOTEIO;
}
return 0;
}
static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
int mxl5005s_writeregs(struct dvb_frontend *fe, u8 *addrtable, u8 *datatable, u8 len)
{
struct mxl5005s_state *state = fe->tuner_priv;
dprintk(1, "%s()\n", __func__);
int ret = 0, i;
*bandwidth = state->Chan_Bandwidth;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
return 0;
for (i = 0 ; i < len-1; i++) {
ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 0);
if (ret < 0)
break;
}
ret = mxl5005s_writereg(fe, addrtable[i], datatable[i], 1);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
return ret;
}
static int mxl5005s_get_status(struct dvb_frontend *fe, u32 *status)
int mxl5005s_init(struct dvb_frontend *fe)
{
dprintk(1, "%s()\n", __func__);
*status = 0;
// *status = TUNER_STATUS_LOCKED;
return 0;
return mxl5005s_reconfigure(fe, MXL_QAM, MXL5005S_BANDWIDTH_6MHZ);
}
static int mxl5005s_init2(struct dvb_frontend *fe)
int mxl5005s_reconfigure(struct dvb_frontend *fe, u32 mod_type, u32 bandwidth)
{
struct mxl5005s_state *state = fe->tuner_priv;
u8 AddrTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
u8 ByteTable[MXL5005S_REG_WRITING_TABLE_LEN_MAX];
int TableLen;
dprintk(1, "%s()\n", __func__);
dprintk(1, "%s(type=%d, bw=%d)\n", __func__, mod_type, bandwidth);
/* Initialize MxL5005S tuner according to MxL5005S tuner example code. */
mxl5005s_reset(fe);
/* Tuner initialization stage 0 */
MXL_GetMasterControl(ByteTable, MC_SYNTH_RESET);
AddrTable[0] = MASTER_CONTROL_ADDR;
ByteTable[0] |= state->config->AgcMasterByte;
mxl5005s_SetRegsWithTable(fe, AddrTable, ByteTable, 1);
mxl5005s_writeregs(fe, AddrTable, ByteTable, 1);
mxl5005s_AssignTunerMode(fe, mod_type, bandwidth);
/* Tuner initialization stage 1 */
MXL_GetInitRegister(fe, AddrTable, ByteTable, &TableLen);
mxl5005s_SetRegsWithTable(fe, AddrTable, ByteTable, TableLen);
mxl5005s_writeregs(fe, AddrTable, ByteTable, TableLen);
return 0;
}
int mxl5005s_AssignTunerMode(struct dvb_frontend *fe, u32 mod_type, u32 bandwidth)
{
struct mxl5005s_state *state = fe->tuner_priv;
struct mxl5005s_config *c = state->config;
InitTunerControls(fe);
/* Set MxL5005S parameters. */
MXL5005_TunerConfig(
fe,
c->mod_mode,
c->if_mode,
bandwidth,
c->if_freq,
c->xtal_freq,
c->agc_mode,
c->top,
c->output_load,
c->clock_out,
c->div_out,
c->cap_select,
c->rssi_enable,
mod_type,
c->tracking_filter);
return 0;
}
static int mxl5005s_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
struct mxl5005s_state *state = fe->tuner_priv;
u32 req_mode, req_bw = 0;
int ret;
dprintk(1, "%s()\n", __func__);
if (fe->ops.info.type == FE_ATSC) {
switch (params->u.vsb.modulation) {
case VSB_8:
req_mode = MXL_ATSC; break;
default:
case QAM_64:
case QAM_256:
case QAM_AUTO:
req_mode = MXL_QAM; break;
}
}
else req_mode = MXL_DVBT;
/* Change tuner for new modulation type if reqd */
if (req_mode != state->current_mode) {
switch (req_mode) {
case VSB_8:
case QAM_64:
case QAM_256:
case QAM_AUTO:
req_bw = MXL5005S_BANDWIDTH_6MHZ;
break;
default:
/* Assume DVB-T */
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
req_bw = MXL5005S_BANDWIDTH_6MHZ;
break;
case BANDWIDTH_7_MHZ:
req_bw = MXL5005S_BANDWIDTH_7MHZ;
break;
case BANDWIDTH_AUTO:
case BANDWIDTH_8_MHZ:
req_bw = MXL5005S_BANDWIDTH_8MHZ;
break;
}
}
state->current_mode = req_mode;
ret = mxl5005s_reconfigure(fe, req_mode, req_bw);
} else
ret = 0;
if (ret == 0) {
dprintk(1, "%s() freq=%d\n", __func__, params->frequency);
ret = mxl5005s_SetRfFreqHz(fe, params->frequency);
}
return ret;
}
static int mxl5005s_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct mxl5005s_state *state = fe->tuner_priv;
dprintk(1, "%s()\n", __func__);
*frequency = state->RF_IN;
return 0;
}
static int mxl5005s_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
{
struct mxl5005s_state *state = fe->tuner_priv;
dprintk(1, "%s()\n", __func__);
*bandwidth = state->Chan_Bandwidth;
return 0;
}
......@@ -4698,7 +4637,6 @@ static const struct dvb_tuner_ops mxl5005s_tuner_ops = {
.set_params = mxl5005s_set_params,
.get_frequency = mxl5005s_get_frequency,
.get_bandwidth = mxl5005s_get_bandwidth,
.get_status = mxl5005s_get_status
};
struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
......@@ -4715,6 +4653,7 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
state->frontend = fe;
state->config = config;
state->i2c = i2c;
state->current_mode = MXL_QAM;
printk(KERN_INFO "MXL5005S: Attached at address 0x%02x\n", config->i2c_address);
......@@ -4726,8 +4665,5 @@ struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
EXPORT_SYMBOL(mxl5005s_attach);
MODULE_DESCRIPTION("MaxLinear MXL5005S silicon tuner driver");
MODULE_AUTHOR("Jan Hoogenraad");
MODULE_AUTHOR("Barnaby Shearer");
MODULE_AUTHOR("Andy Hasper");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
/*
* For the Realtek RTL chip RTL2831U
* Realtek Release Date: 2008-03-14, ver 080314
* Realtek version RTL2831 Linux driver version 080314
* ver 080314
*
* for linux kernel version 2.6.21.4 - 2.6.22-14
* support MXL5005s and MT2060 tuners (support tuner auto-detecting)
* support two IR types -- RC5 and NEC
*
* Known boards with Realtek RTL chip RTL2821U
* Freecom USB stick 14aa:0160 (version 4)
* Conceptronic CTVDIGRCU
*
* Copyright (c) 2008 Realtek
* Copyright (c) 2008 Jan Hoogenraad, Barnaby Shearer, Andy Hasper
* This code is placed under the terms of the GNU General Public License
*
* Released by Realtek under GPLv2.
* Thanks to Realtek for a lot of support we received !
*
* Revision: 080314 - original version
*/
MaxLinear MXL5005S VSB/QAM/DVBT tuner driver
Copyright (C) 2008 MaxLinear
Copyright (C) 2008 Steven Toth <stoth@hauppauge.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __MXL5005S_H
#define __MXL5005S_H
#include <linux/dvb/frontend.h>
/* IF frequency */
enum IF_FREQ_HZ
{
IF_FREQ_4570000HZ = 4570000, ///< IF frequency = 4.57 MHz
IF_FREQ_4571429HZ = 4571429, ///< IF frequency = 4.571 MHz
IF_FREQ_5380000HZ = 5380000, ///< IF frequency = 5.38 MHz
IF_FREQ_36000000HZ = 36000000, ///< IF frequency = 36.000 MHz
IF_FREQ_36125000HZ = 36125000, ///< IF frequency = 36.125 MHz
IF_FREQ_36166667HZ = 36166667, ///< IF frequency = 36.167 MHz
IF_FREQ_44000000HZ = 44000000, ///< IF frequency = 44.000 MHz
};
/* Crystal frequency */
enum CRYSTAL_FREQ_HZ
{
CRYSTAL_FREQ_4000000HZ = 4000000, ///< Crystal frequency = 4.0 MHz
CRYSTAL_FREQ_16000000HZ = 16000000, ///< Crystal frequency = 16.0 MHz
CRYSTAL_FREQ_25000000HZ = 25000000, ///< Crystal frequency = 25.0 MHz
CRYSTAL_FREQ_28800000HZ = 28800000, ///< Crystal frequency = 28.8 MHz
};
struct mxl5005s_config
{
/* 7 bit i2c address */
u8 i2c_address;
#define IF_FREQ_4570000HZ 4570000
#define IF_FREQ_4571429HZ 4571429
#define IF_FREQ_5380000HZ 5380000
#define IF_FREQ_36000000HZ 36000000
#define IF_FREQ_36125000HZ 36125000
#define IF_FREQ_36166667HZ 36166667
#define IF_FREQ_44000000HZ 44000000
u32 if_freq;
#define CRYSTAL_FREQ_4000000HZ 4000000
#define CRYSTAL_FREQ_16000000HZ 16000000
#define CRYSTAL_FREQ_25000000HZ 25000000
#define CRYSTAL_FREQ_28800000HZ 28800000
u32 xtal_freq;
#define MXL_DUAL_AGC 0
#define MXL_SINGLE_AGC 1
u8 agc_mode;
#define MXL_TF_DEFAULT 0
#define MXL_TF_OFF 1
#define MXL_TF_C 2
#define MXL_TF_C_H 3
#define MXL_TF_D 4
#define MXL_TF_D_L 5
#define MXL_TF_E 6
#define MXL_TF_F 7
#define MXL_TF_E_2 8
#define MXL_TF_E_NA 9
#define MXL_TF_G 10
u8 tracking_filter;
#define MXL_RSSI_DISABLE 0
#define MXL_RSSI_ENABLE 1
u8 rssi_enable;
#define MXL_CAP_SEL_DISABLE 0
#define MXL_CAP_SEL_ENABLE 1
u8 cap_select;
#define MXL_DIV_OUT_1 0
#define MXL_DIV_OUT_4 1
u8 div_out;
#define MXL_CLOCK_OUT_DISABLE 0
#define MXL_CLOCK_OUT_ENABLE 1
u8 clock_out;
#define MXL5005S_IF_OUTPUT_LOAD_200_OHM 200
#define MXL5005S_IF_OUTPUT_LOAD_300_OHM 300
u32 output_load;
#define MXL5005S_TOP_5P5 55
#define MXL5005S_TOP_7P2 72
#define MXL5005S_TOP_9P2 92
#define MXL5005S_TOP_11P0 110
#define MXL5005S_TOP_12P9 129
#define MXL5005S_TOP_14P7 147
#define MXL5005S_TOP_16P8 168
#define MXL5005S_TOP_19P4 194
#define MXL5005S_TOP_21P2 212
#define MXL5005S_TOP_23P2 232
#define MXL5005S_TOP_25P2 252
#define MXL5005S_TOP_27P1 271
#define MXL5005S_TOP_29P2 292
#define MXL5005S_TOP_31P7 317
#define MXL5005S_TOP_34P9 349
u32 top;
#define MXL_ANALOG_MODE 0
#define MXL_DIGITAL_MODE 1
u8 mod_mode;
#define MXL_ZERO_IF 0
#define MXL_LOW_IF 1
u8 if_mode;
/* Stuff I don't know what to do with */
u8 AgcMasterByte;
};
#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || (defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
#if defined(CONFIG_MEDIA_TUNER_MXL5005S) || \
(defined(CONFIG_MEDIA_TUNER_MXL5005S_MODULE) && defined(MODULE))
extern struct dvb_frontend *mxl5005s_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
struct mxl5005s_config *config);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment