ngene: add support for Terratec Cynergy 2400i, Dual DVB-T
PATCH RESEND 2/2 ngene: add support for Terratec Cynergy 2400i, Dual DVB-T
[media] ngene: add support for Terratec Cynergy 2400i Dual DVB-T
This code is based on ngene initial check-in (dae52d009fc950b5c209260d50fcc000f5becd3c)
Signed-off-by Patrice Chotard <[email protected]>
--- drivers/media/dvb/ngene/ngene-cards.c | 263 +++++++++++++++++++++++++++++++++ 1 files changed, 263 insertions(+), 0 deletions(-)
drivers/media/dvb/ngene/ngene-cards.c +263 -0
@@ -42,6 +42,8 @@#include "mt2131.h" #include "tda18271c2dd.h" #include "drxk.h" +#include "drxd.h" +#include "dvb-pll.h" /****************************************************************************/
@@ -312,6 +314,235 @@ static int demod_attach_lg330x(struct ngene_channel *chan)return (chan->fe) ?0 : -ENODEV ; } +static int demod_attach_drxd (struct ngene_channel *chan) +{ +struct drxd_config *feconf; + + feconf = chan->dev->card_info->fe_config[chan->number]; + + chan->fe =dvb_attach (drxd_attach, feconf, chan, + &chan->i2c_adapter, &chan->dev->pci_dev->dev); +if (!chan->fe) { +pr_err ("No DRXD found!\n" ); +return -ENODEV ; + } + +if (!dvb_attach (dvb_pll_attach, chan->fe, feconf->pll_address, + &chan->i2c_adapter, + feconf->pll_type)) { +pr_err ("No pll(%d) found!\n" , feconf->pll_type); +return -ENODEV ; + } +return 0 ; +} + +/****************************************************************************/ +/* EEPROM TAGS **************************************************************/ +/****************************************************************************/ + +#define MICNG_EE_START 0x0100 +#define MICNG_EE_END 0x0FF0 + +#define MICNG_EETAG_END0 0x0000 +#define MICNG_EETAG_END1 0xFFFF + +/* 0x0001 - 0x000F reserved for housekeeping */ +/* 0xFFFF - 0xFFFE reserved for housekeeping */ + +/* Micronas assigned tags +EEProm tags for hardware support */ + +#define MICNG_EETAG_DRXD1_OSCDEVIATION 0x1000/* 2 Bytes data */ +#define MICNG_EETAG_DRXD2_OSCDEVIATION 0x1001/* 2 Bytes data */ + +#define MICNG_EETAG_MT2060_1_1STIF 0x1100/* 2 Bytes data */ +#define MICNG_EETAG_MT2060_2_1STIF 0x1101/* 2 Bytes data */ + +/* Tag range for OEMs */ + +#define MICNG_EETAG_OEM_FIRST 0xC000 +#define MICNG_EETAG_OEM_LAST 0xFFEF + +static int i2c_write_eeprom (struct i2c_adapter *adapter, +u8 adr,u16 reg,u8 data) +{ +u8 m[3 ] = {(reg >>8 ), (reg &0xff ), data}; +struct i2c_msg msg = {.addr = adr, .flags =0 , .buf = m, + .len =sizeof (m)}; + +if (i2c_transfer (adapter, &msg,1 ) !=1 ) { +pr_err (DEVICE_NAME ": Error writing EEPROM!\n" ); +return -EIO ; + } +return 0 ; +} + +static int i2c_read_eeprom (struct i2c_adapter *adapter, +u8 adr,u16 reg,u8 *data,int len) +{ +u8 msg[2 ] = {(reg >>8 ), (reg &0xff )}; +struct i2c_msg msgs[2 ] = {{.addr = adr, .flags =0 , + .buf = msg, .len =2 }, + {.addr = adr, .flags =I2C_M_RD , + .buf = data, .len = len} }; + +if (i2c_transfer (adapter, msgs,2 ) !=2 ) { +pr_err (DEVICE_NAME ": Error reading EEPROM\n" ); +return -EIO ; + } +return 0 ; +} + +static int ReadEEProm (struct i2c_adapter *adapter, +u16 Tag,u32 MaxLen,u8 *data,u32 *pLength) +{ +int status =0 ; +u16 Addr =MICNG_EE_START , Length, tag =0 ; +u8 EETag[3 ]; + +while (Addr +sizeof (u16) +1 <MICNG_EE_END ) { +if (i2c_read_eeprom (adapter,0x50 , Addr, EETag,sizeof (EETag))) +return -1 ; + tag = (EETag[0 ] <<8 ) | EETag[1 ]; +if (tag ==MICNG_EETAG_END0 || tag ==MICNG_EETAG_END1 ) +return -1 ; +if (tag == Tag) +break ; + Addr +=sizeof (u16) +1 + EETag[2 ]; + } +if (Addr +sizeof (u16) +1 + EETag[2 ] >MICNG_EE_END ) { +pr_err (DEVICE_NAME +": Reached EOEE @ Tag = %04x Length = %3d\n" , + tag, EETag[2 ]); +return -1 ; + } + Length = EETag[2 ]; +if (Length > MaxLen) + Length = (u16 ) MaxLen; +if (Length >0 ) { + Addr +=sizeof (u16) +1 ; + status =i2c_read_eeprom (adapter,0x50 , Addr, data, Length); +if (!status) { + *pLength = EETag[2 ]; +if (Length < EETag[2 ]) + ;/*status=STATUS_BUFFER_OVERFLOW; */ + } + } +return status; +} + +static int WriteEEProm (struct i2c_adapter *adapter, +u16 Tag,u32 Length,u8 *data) +{ +int status =0 ; +u16 Addr =MICNG_EE_START ; +u8 EETag[3 ]; +u16 tag =0 ; +int retry, i; + +while (Addr +sizeof (u16) +1 <MICNG_EE_END ) { +if (i2c_read_eeprom (adapter,0x50 , Addr, EETag,sizeof (EETag))) +return -1 ; + tag = (EETag[0 ] <<8 ) | EETag[1 ]; +if (tag ==MICNG_EETAG_END0 || tag ==MICNG_EETAG_END1 ) +return -1 ; +if (tag == Tag) +break ; + Addr +=sizeof (u16) +1 + EETag[2 ]; + } +if (Addr +sizeof (u16) +1 + EETag[2 ] >MICNG_EE_END ) { +pr_err (DEVICE_NAME +": Reached EOEE @ Tag = %04x Length = %3d\n" , + tag, EETag[2 ]); +return -1 ; + } + +if (Length > EETag[2 ]) +return -EINVAL ; +/* Note: We write the data one byte at a time to avoid +issues with page sizes. (which are different for +each manufacture and eeprom size) +*/ + Addr +=sizeof (u16) +1 ; +for (i =0 ; i < Length; i++, Addr++) { + status =i2c_write_eeprom (adapter,0x50 , Addr, data[i]); + +if (status) +break ; + +/* Poll for finishing write cycle */ + retry =10 ; +while (retry) { +u8 Tmp; + +msleep (50 ); + status =i2c_read_eeprom (adapter,0x50 , Addr, &Tmp,1 ); +if (status) +break ; +if (Tmp != data[i]) +pr_err (DEVICE_NAME +"eeprom write error\n" ); + retry -=1 ; + } +if (status) { +pr_err (DEVICE_NAME +": Timeout polling eeprom\n" ); +break ; + } + } +return status; +} + +static int eeprom_read_ushort (struct i2c_adapter *adapter,u16 tag,u16 *data) +{ +int stat; +u8 buf[2 ]; +u32 len =0 ; + + stat =ReadEEProm (adapter, tag,2 , buf, &len); +if (stat) +return stat; +if (len !=2 ) +return -EINVAL ; + + *data = (buf[0 ] <<8 ) | buf[1 ]; +return 0 ; +} + +static int eeprom_write_ushort (struct i2c_adapter *adapter,u16 tag,u16 data) +{ +int stat; +u8 buf[2 ]; + + buf[0 ] = data >>8 ; + buf[1 ] = data &0xff ; + stat =WriteEEProm (adapter, tag,2 , buf); +if (stat) +return stat; +return 0 ; +} + +static s16 osc_deviation (void *priv,s16 deviation,int flag) +{ +struct ngene_channel *chan = priv; +struct i2c_adapter *adap = &chan->i2c_adapter; +u16 data =0 ; + +if (flag) { + data = (u16 ) deviation; +pr_info (DEVICE_NAME ": write deviation %d\n" , + deviation); +eeprom_write_ushort (adap,0x1000 + chan->number, data); + }else { +if (eeprom_read_ushort (adap,0x1000 + chan->number, &data)) + data =0 ; +pr_info (DEVICE_NAME ": read deviation %d\n" , + (s16 ) data); + } + +return (s16 ) data; +} +/****************************************************************************/ /* Switch control (I2C gates, etc.) *****************************************/ /****************************************************************************/
@@ -463,6 +694,37 @@ static struct ngene_info ngene_info_m780 = { .fw_version = 15, }; +static struct drxd_config fe_terratec_dvbt_0 = { + .index =0 , + .demod_address =0x70 , + .demod_revision =0xa2 , + .demoda_address =0x00 , + .pll_address =0x60 , + .pll_type =DVB_PLL_THOMSON_DTT7520X , + .clock =20000 , + .osc_deviation = osc_deviation, +}; + +static struct drxd_config fe_terratec_dvbt_1 = { + .index =1 , + .demod_address =0x71 , + .demod_revision =0xa2 , + .demoda_address =0x00 , + .pll_address =0x60 , + .pll_type =DVB_PLL_THOMSON_DTT7520X , + .clock =20000 , + .osc_deviation = osc_deviation, +}; + +static struct ngene_info ngene_info_terratec = { + .type =NGENE_TERRATEC , + .name ="Terratec Integra/Cinergy2400i Dual DVB-T" , + .io_type = {NGENE_IO_TSIN ,NGENE_IO_TSIN }, + .demod_attach = {demod_attach_drxd, demod_attach_drxd}, + .fe_config = {&fe_terratec_dvbt_0, &fe_terratec_dvbt_1}, + .i2c_access =1 , +}; +/****************************************************************************/
@@ -487,6 +749,7 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {NGENE_ID (0x18c3 ,0xdd10 , ngene_info_duoFlex),NGENE_ID (0x18c3 ,0xdd20 , ngene_info_duoFlex),NGENE_ID (0x1461 ,0x062e , ngene_info_m780), +NGENE_ID (0x153b ,0x1167 , ngene_info_terratec), {0} };MODULE_DEVICE_TABLE (pci, ngene_id_tbl);
Signature · 1 line
1.7.9.1