diff options
author | Ralph Metzler <rmetzler@digitaldevices.de> | 2011-07-03 12:55:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-07-27 16:55:42 -0400 |
commit | 9ca9efb077505b5b717fc15eab33c44d17eb76f7 (patch) | |
tree | f6718f8aaab45032a4c6559274d7c27b2367fe60 /drivers/media/dvb/ngene | |
parent | f9004df79ffd361312d4b5d237d56c2f64caa1a3 (diff) |
[media] ngene: Support Digital Devices DuoFlex CT
Support Digital Devices DuoFlex CT with ngene.
Signed-off-by: Ralph Metzler <rmetzler@digitaldevices.de>
Signed-off-by: Oliver Endriss <o.endriss@gmx.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/ngene')
-rw-r--r-- | drivers/media/dvb/ngene/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/dvb/ngene/ngene-cards.c | 176 | ||||
-rw-r--r-- | drivers/media/dvb/ngene/ngene-core.c | 15 | ||||
-rw-r--r-- | drivers/media/dvb/ngene/ngene.h | 3 |
4 files changed, 156 insertions, 40 deletions
diff --git a/drivers/media/dvb/ngene/Kconfig b/drivers/media/dvb/ngene/Kconfig index cec242b7c00d..64c84702ba5c 100644 --- a/drivers/media/dvb/ngene/Kconfig +++ b/drivers/media/dvb/ngene/Kconfig | |||
@@ -5,6 +5,8 @@ config DVB_NGENE | |||
5 | select DVB_STV6110x if !DVB_FE_CUSTOMISE | 5 | select DVB_STV6110x if !DVB_FE_CUSTOMISE |
6 | select DVB_STV090x if !DVB_FE_CUSTOMISE | 6 | select DVB_STV090x if !DVB_FE_CUSTOMISE |
7 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE | 7 | select DVB_LGDT330X if !DVB_FE_CUSTOMISE |
8 | select DVB_DRXK if !DVB_FE_CUSTOMISE | ||
9 | select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE | ||
8 | select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE | 10 | select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE |
9 | ---help--- | 11 | ---help--- |
10 | Support for Micronas PCI express cards with nGene bridge. | 12 | Support for Micronas PCI express cards with nGene bridge. |
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c index fcf4be901ec8..ca2e146f1b8f 100644 --- a/drivers/media/dvb/ngene/ngene-cards.c +++ b/drivers/media/dvb/ngene/ngene-cards.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "lnbh24.h" | 40 | #include "lnbh24.h" |
41 | #include "lgdt330x.h" | 41 | #include "lgdt330x.h" |
42 | #include "mt2131.h" | 42 | #include "mt2131.h" |
43 | #include "drxk.h" | ||
43 | 44 | ||
44 | 45 | ||
45 | /****************************************************************************/ | 46 | /****************************************************************************/ |
@@ -83,6 +84,52 @@ static int tuner_attach_stv6110(struct ngene_channel *chan) | |||
83 | } | 84 | } |
84 | 85 | ||
85 | 86 | ||
87 | static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) | ||
88 | { | ||
89 | struct ngene_channel *chan = fe->sec_priv; | ||
90 | int status; | ||
91 | |||
92 | if (enable) { | ||
93 | down(&chan->dev->pll_mutex); | ||
94 | status = chan->gate_ctrl(fe, 1); | ||
95 | } else { | ||
96 | status = chan->gate_ctrl(fe, 0); | ||
97 | up(&chan->dev->pll_mutex); | ||
98 | } | ||
99 | return status; | ||
100 | } | ||
101 | |||
102 | struct dvb_frontend *tda18271c2dd_attach(struct dvb_frontend *fe, | ||
103 | struct i2c_adapter *i2c, u8 adr); | ||
104 | |||
105 | static int tuner_attach_tda18271(struct ngene_channel *chan) | ||
106 | { | ||
107 | struct i2c_adapter *i2c; | ||
108 | struct dvb_frontend *fe; | ||
109 | |||
110 | i2c = &chan->dev->channel[0].i2c_adapter; | ||
111 | if (chan->fe->ops.i2c_gate_ctrl) | ||
112 | chan->fe->ops.i2c_gate_ctrl(chan->fe, 1); | ||
113 | fe = dvb_attach(tda18271c2dd_attach, chan->fe, i2c, 0x60); | ||
114 | if (chan->fe->ops.i2c_gate_ctrl) | ||
115 | chan->fe->ops.i2c_gate_ctrl(chan->fe, 0); | ||
116 | if (!fe) { | ||
117 | printk("No TDA18271 found!\n"); | ||
118 | return -ENODEV; | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int tuner_attach_probe(struct ngene_channel *chan) | ||
125 | { | ||
126 | if (chan->demod_type == 0) | ||
127 | return tuner_attach_stv6110(chan); | ||
128 | if (chan->demod_type == 1) | ||
129 | return tuner_attach_tda18271(chan); | ||
130 | return -EINVAL; | ||
131 | } | ||
132 | |||
86 | static int demod_attach_stv0900(struct ngene_channel *chan) | 133 | static int demod_attach_stv0900(struct ngene_channel *chan) |
87 | { | 134 | { |
88 | struct i2c_adapter *i2c; | 135 | struct i2c_adapter *i2c; |
@@ -130,6 +177,60 @@ static void cineS2_tuner_i2c_lock(struct dvb_frontend *fe, int lock) | |||
130 | up(&chan->dev->pll_mutex); | 177 | up(&chan->dev->pll_mutex); |
131 | } | 178 | } |
132 | 179 | ||
180 | static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) | ||
181 | { | ||
182 | struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, | ||
183 | .buf = val, .len = 1 }}; | ||
184 | return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; | ||
185 | } | ||
186 | |||
187 | static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, | ||
188 | u16 reg, u8 *val) | ||
189 | { | ||
190 | u8 msg[2] = {reg>>8, reg&0xff}; | ||
191 | struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, | ||
192 | .buf = msg, .len = 2}, | ||
193 | {.addr = adr, .flags = I2C_M_RD, | ||
194 | .buf = val, .len = 1}}; | ||
195 | return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; | ||
196 | } | ||
197 | |||
198 | static int port_has_stv0900(struct i2c_adapter *i2c, int port) | ||
199 | { | ||
200 | u8 val; | ||
201 | if (i2c_read_reg16(i2c, 0x68+port/2, 0xf100, &val) < 0) | ||
202 | return 0; | ||
203 | return 1; | ||
204 | } | ||
205 | |||
206 | static int port_has_drxk(struct i2c_adapter *i2c, int port) | ||
207 | { | ||
208 | u8 val; | ||
209 | |||
210 | if (i2c_read(i2c, 0x29+port, &val) < 0) | ||
211 | return 0; | ||
212 | printk("DRXK@%02x\n", 0x29+port); | ||
213 | return 1; | ||
214 | } | ||
215 | |||
216 | static int demod_attach_drxk(struct ngene_channel *chan, | ||
217 | struct i2c_adapter *i2c) | ||
218 | { | ||
219 | struct dvb_frontend *fe; | ||
220 | |||
221 | chan->fe = fe = dvb_attach(drxk_attach, | ||
222 | i2c, 0x29 + (chan->number^2), | ||
223 | &chan->fe2); | ||
224 | if (!chan->fe) { | ||
225 | printk("No DRXK found!\n"); | ||
226 | return -ENODEV; | ||
227 | } | ||
228 | fe->sec_priv = chan; | ||
229 | chan->gate_ctrl = fe->ops.i2c_gate_ctrl; | ||
230 | fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; | ||
231 | return 0; | ||
232 | } | ||
233 | |||
133 | static int cineS2_probe(struct ngene_channel *chan) | 234 | static int cineS2_probe(struct ngene_channel *chan) |
134 | { | 235 | { |
135 | struct i2c_adapter *i2c; | 236 | struct i2c_adapter *i2c; |
@@ -144,43 +245,42 @@ static int cineS2_probe(struct ngene_channel *chan) | |||
144 | else | 245 | else |
145 | i2c = &chan->dev->channel[1].i2c_adapter; | 246 | i2c = &chan->dev->channel[1].i2c_adapter; |
146 | 247 | ||
147 | fe_conf = chan->dev->card_info->fe_config[chan->number]; | 248 | if (port_has_stv0900(i2c, chan->number)) { |
148 | i2c_msg.addr = fe_conf->address; | 249 | chan->demod_type=0; |
149 | 250 | fe_conf = chan->dev->card_info->fe_config[chan->number]; | |
150 | /* probe demod */ | 251 | /* demod found, attach it */ |
151 | i2c_msg.len = 2; | 252 | rc = demod_attach_stv0900(chan); |
152 | buf[0] = 0xf1; | 253 | if (rc < 0 || chan->number < 2) |
153 | buf[1] = 0x00; | 254 | return rc; |
154 | rc = i2c_transfer(i2c, &i2c_msg, 1); | 255 | |
155 | if (rc != 1) | 256 | /* demod #2: reprogram outputs DPN1 & DPN2 */ |
156 | return -ENODEV; | 257 | i2c_msg.addr = fe_conf->address; |
157 | 258 | i2c_msg.len = 3; | |
158 | /* demod found, attach it */ | 259 | buf[0] = 0xf1; |
159 | rc = demod_attach_stv0900(chan); | 260 | switch (chan->number) |
160 | if (rc < 0 || chan->number < 2) | 261 | { |
161 | return rc; | 262 | case 2: |
162 | 263 | buf[1] = 0x5c; | |
163 | /* demod #2: reprogram outputs DPN1 & DPN2 */ | 264 | buf[2] = 0xc2; |
164 | i2c_msg.len = 3; | 265 | break; |
165 | buf[0] = 0xf1; | 266 | case 3: |
166 | switch (chan->number) { | 267 | buf[1] = 0x61; |
167 | case 2: | 268 | buf[2] = 0xcc; |
168 | buf[1] = 0x5c; | 269 | break; |
169 | buf[2] = 0xc2; | 270 | default: |
170 | break; | 271 | return -ENODEV; |
171 | case 3: | 272 | } |
172 | buf[1] = 0x61; | 273 | rc = i2c_transfer(i2c, &i2c_msg, 1); |
173 | buf[2] = 0xcc; | 274 | if (rc != 1) { |
174 | break; | 275 | printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); |
175 | default: | 276 | return -EIO; |
176 | return -ENODEV; | 277 | } |
278 | } else if (port_has_drxk(i2c, chan->number^2)) { | ||
279 | chan->demod_type=1; | ||
280 | demod_attach_drxk(chan, i2c); | ||
281 | } else { | ||
282 | printk("No demod found on chan %d\n", chan->number); | ||
177 | } | 283 | } |
178 | rc = i2c_transfer(i2c, &i2c_msg, 1); | ||
179 | if (rc != 1) { | ||
180 | printk(KERN_ERR DEVICE_NAME ": could not setup DPNx\n"); | ||
181 | return -EIO; | ||
182 | } | ||
183 | |||
184 | return 0; | 284 | return 0; |
185 | } | 285 | } |
186 | 286 | ||
@@ -337,7 +437,7 @@ static struct ngene_info ngene_info_duoFlexS2 = { | |||
337 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, | 437 | .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, NGENE_IO_TSIN, |
338 | NGENE_IO_TSOUT}, | 438 | NGENE_IO_TSOUT}, |
339 | .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, | 439 | .demod_attach = {cineS2_probe, cineS2_probe, cineS2_probe, cineS2_probe}, |
340 | .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110, tuner_attach_stv6110}, | 440 | .tuner_attach = {tuner_attach_probe, tuner_attach_probe, tuner_attach_probe, tuner_attach_probe}, |
341 | .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, | 441 | .fe_config = {&fe_cineS2, &fe_cineS2, &fe_cineS2_2, &fe_cineS2_2}, |
342 | .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, | 442 | .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1, &tuner_cineS2_0, &tuner_cineS2_1}, |
343 | .lnb = {0x0a, 0x08, 0x0b, 0x09}, | 443 | .lnb = {0x0a, 0x08, 0x0b, 0x09}, |
@@ -397,7 +497,7 @@ MODULE_DEVICE_TABLE(pci, ngene_id_tbl); | |||
397 | /****************************************************************************/ | 497 | /****************************************************************************/ |
398 | 498 | ||
399 | static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, | 499 | static pci_ers_result_t ngene_error_detected(struct pci_dev *dev, |
400 | enum pci_channel_state state) | 500 | enum pci_channel_state state) |
401 | { | 501 | { |
402 | printk(KERN_ERR DEVICE_NAME ": PCI error\n"); | 502 | printk(KERN_ERR DEVICE_NAME ": PCI error\n"); |
403 | if (state == pci_channel_io_perm_failure) | 503 | if (state == pci_channel_io_perm_failure) |
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c index 6927c726ce35..c59bf5057a40 100644 --- a/drivers/media/dvb/ngene/ngene-core.c +++ b/drivers/media/dvb/ngene/ngene-core.c | |||
@@ -41,7 +41,7 @@ | |||
41 | 41 | ||
42 | #include "ngene.h" | 42 | #include "ngene.h" |
43 | 43 | ||
44 | static int one_adapter = 1; | 44 | static int one_adapter = 0; |
45 | module_param(one_adapter, int, 0444); | 45 | module_param(one_adapter, int, 0444); |
46 | MODULE_PARM_DESC(one_adapter, "Use only one adapter."); | 46 | MODULE_PARM_DESC(one_adapter, "Use only one adapter."); |
47 | 47 | ||
@@ -461,7 +461,7 @@ static u8 TSFeatureDecoderSetup[8 * 5] = { | |||
461 | 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, | 461 | 0x42, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, |
462 | 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ | 462 | 0x40, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXH */ |
463 | 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ | 463 | 0x71, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* DRXHser */ |
464 | 0x72, 0x06, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ | 464 | 0x72, 0x00, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* S2ser */ |
465 | 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ | 465 | 0x40, 0x07, 0x00, 0x02, 0x02, 0xbc, 0x00, 0x00, /* LGDT3303 */ |
466 | }; | 466 | }; |
467 | 467 | ||
@@ -1443,6 +1443,9 @@ static void release_channel(struct ngene_channel *chan) | |||
1443 | chan->ci_dev = NULL; | 1443 | chan->ci_dev = NULL; |
1444 | } | 1444 | } |
1445 | 1445 | ||
1446 | if (chan->fe2) { | ||
1447 | dvb_unregister_frontend(chan->fe2); | ||
1448 | } | ||
1446 | if (chan->fe) { | 1449 | if (chan->fe) { |
1447 | dvb_unregister_frontend(chan->fe); | 1450 | dvb_unregister_frontend(chan->fe); |
1448 | dvb_frontend_detach(chan->fe); | 1451 | dvb_frontend_detach(chan->fe); |
@@ -1534,6 +1537,14 @@ static int init_channel(struct ngene_channel *chan) | |||
1534 | goto err; | 1537 | goto err; |
1535 | chan->has_demux = true; | 1538 | chan->has_demux = true; |
1536 | } | 1539 | } |
1540 | if (chan->fe2) { | ||
1541 | if (dvb_register_frontend(adapter, chan->fe2) < 0) | ||
1542 | goto err; | ||
1543 | chan->fe2->tuner_priv=chan->fe->tuner_priv; | ||
1544 | memcpy(&chan->fe2->ops.tuner_ops, | ||
1545 | &chan->fe->ops.tuner_ops, | ||
1546 | sizeof(struct dvb_tuner_ops)); | ||
1547 | } | ||
1537 | 1548 | ||
1538 | if (chan->has_demux) { | 1549 | if (chan->has_demux) { |
1539 | ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", | 1550 | ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", |
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h index 40fce9e3ae66..e8cd93deba5a 100644 --- a/drivers/media/dvb/ngene/ngene.h +++ b/drivers/media/dvb/ngene/ngene.h | |||
@@ -641,8 +641,11 @@ struct ngene_channel { | |||
641 | int mode; | 641 | int mode; |
642 | bool has_adapter; | 642 | bool has_adapter; |
643 | bool has_demux; | 643 | bool has_demux; |
644 | int demod_type; | ||
645 | int (*gate_ctrl)(struct dvb_frontend *, int); | ||
644 | 646 | ||
645 | struct dvb_frontend *fe; | 647 | struct dvb_frontend *fe; |
648 | struct dvb_frontend *fe2; | ||
646 | struct dmxdev dmxdev; | 649 | struct dmxdev dmxdev; |
647 | struct dvb_demux demux; | 650 | struct dvb_demux demux; |
648 | struct dvb_net dvbnet; | 651 | struct dvb_net dvbnet; |