ngene: add support for Terratec Cynergy 2400i, Dual DVB-T
PATCH 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)
--- drivers/media/dvb/ngene/ngene-cards.c | 263 +++++++++++++++++++++++++++++++++ 1 files changed, 263 insertions(+), 0 deletions(-)
(quoted diff) +0 -0
b/drivers/media/dvb/ngene/ngene-cards.c
index 7539a5d..08c610f 100644
drivers/media/dvb/ngene/ngene-cards.c +2 -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);
Em 29-07-2012 17:50, Patrice Chotard escreveu:
Quoted 2 lines
[media] ngene: add support for Terratec Cynergy 2400i
Dual DVB-T
Sorry, but the patch got line wrapped. Please re-send this patch series.
Thanks!
Mauro
Quoted 317 lines
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 +198
-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)
drivers/media/dvb/ngene/ngene-cards.c +33
-0+{ +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.) *****************************************/
/****************************************************************************/drivers/media/dvb/ngene/ngene-cards.c +32
-0@@ -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);
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html