]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
2add87a9 | 2 | /* |
d66b94b4 PB |
3 | * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III |
4 | * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling | |
5 | * see flexcop.c for copyright information | |
2add87a9 | 6 | */ |
827855d3 | 7 | #include <media/tuner.h> |
2add87a9 | 8 | #include "flexcop.h" |
2add87a9 | 9 | #include "mt312.h" |
d66b94b4 | 10 | #include "stv0299.h" |
ca19aaa5 PB |
11 | #include "s5h1420.h" |
12 | #include "itd1000.h" | |
c9dd82c2 | 13 | #include "cx24113.h" |
d66b94b4 | 14 | #include "cx24123.h" |
c9dd82c2 | 15 | #include "isl6421.h" |
5afc9a25 | 16 | #include "cx24120.h" |
d66b94b4 PB |
17 | #include "mt352.h" |
18 | #include "bcm3510.h" | |
19 | #include "nxt200x.h" | |
20 | #include "dvb-pll.h" | |
21 | #include "lgdt330x.h" | |
22 | #include "tuner-simple.h" | |
23 | #include "stv0297.h" | |
c9dd82c2 | 24 | |
68b7f761 TP |
25 | |
26 | /* Can we use the specified front-end? Remember that if we are compiled | |
27 | * into the kernel we can't call code that's in modules. */ | |
30f895a9 | 28 | #define FE_SUPPORTED(fe) IS_REACHABLE(CONFIG_DVB_ ## fe) |
68b7f761 | 29 | |
4b7574fb | 30 | #if FE_SUPPORTED(BCM3510) || (FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421)) |
5afc9a25 JD |
31 | static int flexcop_fe_request_firmware(struct dvb_frontend *fe, |
32 | const struct firmware **fw, char *name) | |
33 | { | |
34 | struct flexcop_device *fc = fe->dvb->priv; | |
35 | ||
36 | return request_firmware(fw, name, fc->dev); | |
37 | } | |
38 | #endif | |
39 | ||
2add87a9 | 40 | /* lnb control */ |
733d0def | 41 | #if (FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)) && FE_SUPPORTED(PLL) |
0df289a2 MCC |
42 | static int flexcop_set_voltage(struct dvb_frontend *fe, |
43 | enum fe_sec_voltage voltage) | |
2add87a9 JS |
44 | { |
45 | struct flexcop_device *fc = fe->dvb->priv; | |
46 | flexcop_ibi_value v; | |
47 | deb_tuner("polarity/voltage = %u\n", voltage); | |
48 | ||
49 | v = fc->read_ibi_reg(fc, misc_204); | |
50 | switch (voltage) { | |
d66b94b4 PB |
51 | case SEC_VOLTAGE_OFF: |
52 | v.misc_204.ACPI1_sig = 1; | |
53 | break; | |
54 | case SEC_VOLTAGE_13: | |
55 | v.misc_204.ACPI1_sig = 0; | |
56 | v.misc_204.LNB_L_H_sig = 0; | |
57 | break; | |
58 | case SEC_VOLTAGE_18: | |
59 | v.misc_204.ACPI1_sig = 0; | |
60 | v.misc_204.LNB_L_H_sig = 1; | |
61 | break; | |
62 | default: | |
63 | err("unknown SEC_VOLTAGE value"); | |
64 | return -EINVAL; | |
2add87a9 JS |
65 | } |
66 | return fc->write_ibi_reg(fc, misc_204, v); | |
67 | } | |
d66b94b4 | 68 | #endif |
2add87a9 | 69 | |
68b7f761 | 70 | #if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312) |
733d0def | 71 | static int __maybe_unused flexcop_sleep(struct dvb_frontend* fe) |
2add87a9 JS |
72 | { |
73 | struct flexcop_device *fc = fe->dvb->priv; | |
2add87a9 JS |
74 | if (fc->fe_sleep) |
75 | return fc->fe_sleep(fe); | |
2add87a9 JS |
76 | return 0; |
77 | } | |
d66b94b4 | 78 | #endif |
2add87a9 | 79 | |
d66b94b4 | 80 | /* SkyStar2 DVB-S rev 2.3 */ |
016e53de | 81 | #if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL) |
0df289a2 | 82 | static int flexcop_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone) |
2add87a9 | 83 | { |
d66b94b4 | 84 | /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */ |
2add87a9 JS |
85 | struct flexcop_device *fc = fe->dvb->priv; |
86 | flexcop_ibi_value v; | |
87 | u16 ax; | |
88 | v.raw = 0; | |
2add87a9 JS |
89 | deb_tuner("tone = %u\n",tone); |
90 | ||
91 | switch (tone) { | |
d66b94b4 PB |
92 | case SEC_TONE_ON: |
93 | ax = 0x01ff; | |
94 | break; | |
95 | case SEC_TONE_OFF: | |
96 | ax = 0; | |
97 | break; | |
98 | default: | |
99 | err("unknown SEC_TONE value"); | |
100 | return -EINVAL; | |
2add87a9 JS |
101 | } |
102 | ||
103 | v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */ | |
958706c1 JS |
104 | v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax; |
105 | v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax; | |
2add87a9 JS |
106 | return fc->write_ibi_reg(fc,lnb_switch_freq_200,v); |
107 | } | |
108 | ||
109 | static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data) | |
110 | { | |
111 | flexcop_set_tone(fe, SEC_TONE_ON); | |
112 | udelay(data ? 500 : 1000); | |
113 | flexcop_set_tone(fe, SEC_TONE_OFF); | |
114 | udelay(data ? 1000 : 500); | |
115 | } | |
116 | ||
117 | static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data) | |
118 | { | |
119 | int i, par = 1, d; | |
2add87a9 JS |
120 | for (i = 7; i >= 0; i--) { |
121 | d = (data >> i) & 1; | |
122 | par ^= d; | |
123 | flexcop_diseqc_send_bit(fe, d); | |
124 | } | |
2add87a9 JS |
125 | flexcop_diseqc_send_bit(fe, par); |
126 | } | |
127 | ||
d66b94b4 PB |
128 | static int flexcop_send_diseqc_msg(struct dvb_frontend *fe, |
129 | int len, u8 *msg, unsigned long burst) | |
2add87a9 JS |
130 | { |
131 | int i; | |
132 | ||
133 | flexcop_set_tone(fe, SEC_TONE_OFF); | |
134 | mdelay(16); | |
135 | ||
136 | for (i = 0; i < len; i++) | |
137 | flexcop_diseqc_send_byte(fe,msg[i]); | |
2add87a9 JS |
138 | mdelay(16); |
139 | ||
140 | if (burst != -1) { | |
141 | if (burst) | |
142 | flexcop_diseqc_send_byte(fe, 0xff); | |
143 | else { | |
144 | flexcop_set_tone(fe, SEC_TONE_ON); | |
c4e3fd94 TM |
145 | mdelay(12); |
146 | udelay(500); | |
2add87a9 JS |
147 | flexcop_set_tone(fe, SEC_TONE_OFF); |
148 | } | |
149 | msleep(20); | |
150 | } | |
151 | return 0; | |
152 | } | |
153 | ||
d66b94b4 PB |
154 | static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe, |
155 | struct dvb_diseqc_master_cmd *cmd) | |
2add87a9 JS |
156 | { |
157 | return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0); | |
158 | } | |
159 | ||
d66b94b4 | 160 | static int flexcop_diseqc_send_burst(struct dvb_frontend *fe, |
0df289a2 | 161 | enum fe_sec_mini_cmd minicmd) |
2add87a9 JS |
162 | { |
163 | return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd); | |
164 | } | |
165 | ||
d66b94b4 PB |
166 | static struct mt312_config skystar23_samsung_tbdu18132_config = { |
167 | .demod_address = 0x0e, | |
168 | }; | |
169 | ||
eccd15aa | 170 | static int skystar2_rev23_attach(struct flexcop_device *fc, |
d66b94b4 PB |
171 | struct i2c_adapter *i2c) |
172 | { | |
016e53de TP |
173 | struct dvb_frontend_ops *ops; |
174 | ||
eccd15aa | 175 | fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c); |
016e53de TP |
176 | if (!fc->fe) |
177 | return 0; | |
178 | ||
179 | if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, | |
180 | DVB_PLL_SAMSUNG_TBDU18132)) | |
181 | return 0; | |
182 | ||
183 | ops = &fc->fe->ops; | |
184 | ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; | |
185 | ops->diseqc_send_burst = flexcop_diseqc_send_burst; | |
186 | ops->set_tone = flexcop_set_tone; | |
187 | ops->set_voltage = flexcop_set_voltage; | |
188 | fc->fe_sleep = ops->sleep; | |
189 | ops->sleep = flexcop_sleep; | |
190 | return 1; | |
d66b94b4 | 191 | } |
68b7f761 TP |
192 | #else |
193 | #define skystar2_rev23_attach NULL | |
d66b94b4 PB |
194 | #endif |
195 | ||
196 | /* SkyStar2 DVB-S rev 2.6 */ | |
016e53de | 197 | #if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL) |
d66b94b4 PB |
198 | static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe, |
199 | u32 srate, u32 ratio) | |
2add87a9 JS |
200 | { |
201 | u8 aclk = 0; | |
202 | u8 bclk = 0; | |
203 | ||
d66b94b4 PB |
204 | if (srate < 1500000) { |
205 | aclk = 0xb7; bclk = 0x47; | |
206 | } else if (srate < 3000000) { | |
207 | aclk = 0xb7; bclk = 0x4b; | |
208 | } else if (srate < 7000000) { | |
209 | aclk = 0xb7; bclk = 0x4f; | |
210 | } else if (srate < 14000000) { | |
211 | aclk = 0xb7; bclk = 0x53; | |
212 | } else if (srate < 30000000) { | |
213 | aclk = 0xb6; bclk = 0x53; | |
214 | } else if (srate < 45000000) { | |
215 | aclk = 0xb4; bclk = 0x51; | |
216 | } | |
2add87a9 | 217 | |
d66b94b4 PB |
218 | stv0299_writereg(fe, 0x13, aclk); |
219 | stv0299_writereg(fe, 0x14, bclk); | |
220 | stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff); | |
221 | stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff); | |
222 | stv0299_writereg(fe, 0x21, ratio & 0xf0); | |
2add87a9 JS |
223 | return 0; |
224 | } | |
225 | ||
2add87a9 | 226 | static u8 samsung_tbmu24112_inittab[] = { |
d66b94b4 PB |
227 | 0x01, 0x15, |
228 | 0x02, 0x30, | |
229 | 0x03, 0x00, | |
230 | 0x04, 0x7D, | |
231 | 0x05, 0x35, | |
232 | 0x06, 0x02, | |
233 | 0x07, 0x00, | |
234 | 0x08, 0xC3, | |
235 | 0x0C, 0x00, | |
236 | 0x0D, 0x81, | |
237 | 0x0E, 0x23, | |
238 | 0x0F, 0x12, | |
239 | 0x10, 0x7E, | |
240 | 0x11, 0x84, | |
241 | 0x12, 0xB9, | |
242 | 0x13, 0x88, | |
243 | 0x14, 0x89, | |
244 | 0x15, 0xC9, | |
245 | 0x16, 0x00, | |
246 | 0x17, 0x5C, | |
247 | 0x18, 0x00, | |
248 | 0x19, 0x00, | |
249 | 0x1A, 0x00, | |
250 | 0x1C, 0x00, | |
251 | 0x1D, 0x00, | |
252 | 0x1E, 0x00, | |
253 | 0x1F, 0x3A, | |
254 | 0x20, 0x2E, | |
255 | 0x21, 0x80, | |
256 | 0x22, 0xFF, | |
257 | 0x23, 0xC1, | |
258 | 0x28, 0x00, | |
259 | 0x29, 0x1E, | |
260 | 0x2A, 0x14, | |
261 | 0x2B, 0x0F, | |
262 | 0x2C, 0x09, | |
263 | 0x2D, 0x05, | |
264 | 0x31, 0x1F, | |
265 | 0x32, 0x19, | |
266 | 0x33, 0xFE, | |
267 | 0x34, 0x93, | |
268 | 0xff, 0xff, | |
2add87a9 JS |
269 | }; |
270 | ||
271 | static struct stv0299_config samsung_tbmu24112_config = { | |
272 | .demod_address = 0x68, | |
273 | .inittab = samsung_tbmu24112_inittab, | |
274 | .mclk = 88000000UL, | |
275 | .invert = 0, | |
2add87a9 | 276 | .skip_reinit = 0, |
da2c7f66 | 277 | .lock_output = STV0299_LOCKOUTPUT_LK, |
2add87a9 JS |
278 | .volt13_op0_op1 = STV0299_VOLT13_OP1, |
279 | .min_delay_ms = 100, | |
280 | .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, | |
2add87a9 JS |
281 | }; |
282 | ||
eccd15aa | 283 | static int skystar2_rev26_attach(struct flexcop_device *fc, |
d66b94b4 | 284 | struct i2c_adapter *i2c) |
2add87a9 | 285 | { |
d66b94b4 | 286 | fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c); |
016e53de TP |
287 | if (!fc->fe) |
288 | return 0; | |
289 | ||
290 | if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c, | |
291 | DVB_PLL_SAMSUNG_TBMU24112)) | |
292 | return 0; | |
293 | ||
294 | fc->fe->ops.set_voltage = flexcop_set_voltage; | |
295 | fc->fe_sleep = fc->fe->ops.sleep; | |
296 | fc->fe->ops.sleep = flexcop_sleep; | |
297 | return 1; | |
298 | ||
d66b94b4 | 299 | } |
68b7f761 TP |
300 | #else |
301 | #define skystar2_rev26_attach NULL | |
d66b94b4 PB |
302 | #endif |
303 | ||
304 | /* SkyStar2 DVB-S rev 2.7 */ | |
68b7f761 | 305 | #if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000) |
d66b94b4 PB |
306 | static struct s5h1420_config skystar2_rev2_7_s5h1420_config = { |
307 | .demod_address = 0x53, | |
308 | .invert = 1, | |
309 | .repeated_start_workaround = 1, | |
310 | .serial_mpeg = 1, | |
311 | }; | |
312 | ||
313 | static struct itd1000_config skystar2_rev2_7_itd1000_config = { | |
314 | .i2c_address = 0x61, | |
315 | }; | |
316 | ||
eccd15aa | 317 | static int skystar2_rev27_attach(struct flexcop_device *fc, |
d66b94b4 PB |
318 | struct i2c_adapter *i2c) |
319 | { | |
eccd15aa TP |
320 | flexcop_ibi_value r108; |
321 | struct i2c_adapter *i2c_tuner; | |
322 | ||
d66b94b4 PB |
323 | /* enable no_base_addr - no repeated start when reading */ |
324 | fc->fc_i2c_adap[0].no_base_addr = 1; | |
eccd15aa TP |
325 | fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, |
326 | i2c); | |
327 | if (!fc->fe) | |
328 | goto fail; | |
d66b94b4 | 329 | |
eccd15aa TP |
330 | i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe); |
331 | if (!i2c_tuner) | |
332 | goto fail; | |
333 | ||
334 | fc->fe_sleep = fc->fe->ops.sleep; | |
335 | fc->fe->ops.sleep = flexcop_sleep; | |
336 | ||
337 | /* enable no_base_addr - no repeated start when reading */ | |
338 | fc->fc_i2c_adap[2].no_base_addr = 1; | |
339 | if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, | |
48a8a03b | 340 | 0x08, 1, 1, false)) { |
eccd15aa TP |
341 | err("ISL6421 could NOT be attached"); |
342 | goto fail_isl; | |
343 | } | |
344 | info("ISL6421 successfully attached"); | |
345 | ||
346 | /* the ITD1000 requires a lower i2c clock - is it a problem ? */ | |
347 | r108.raw = 0x00000506; | |
348 | fc->write_ibi_reg(fc, tw_sm_c_108, r108); | |
349 | if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner, | |
350 | &skystar2_rev2_7_itd1000_config)) { | |
351 | err("ITD1000 could NOT be attached"); | |
352 | /* Should i2c clock be restored? */ | |
353 | goto fail_isl; | |
354 | } | |
355 | info("ITD1000 successfully attached"); | |
356 | ||
357 | return 1; | |
358 | ||
359 | fail_isl: | |
360 | fc->fc_i2c_adap[2].no_base_addr = 0; | |
361 | fail: | |
362 | /* for the next devices we need it again */ | |
363 | fc->fc_i2c_adap[0].no_base_addr = 0; | |
364 | return 0; | |
d66b94b4 | 365 | } |
68b7f761 TP |
366 | #else |
367 | #define skystar2_rev27_attach NULL | |
d66b94b4 PB |
368 | #endif |
369 | ||
370 | /* SkyStar2 rev 2.8 */ | |
68b7f761 | 371 | #if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113) |
d66b94b4 PB |
372 | static struct cx24123_config skystar2_rev2_8_cx24123_config = { |
373 | .demod_address = 0x55, | |
374 | .dont_use_pll = 1, | |
375 | .agc_callback = cx24113_agc_callback, | |
376 | }; | |
377 | ||
378 | static const struct cx24113_config skystar2_rev2_8_cx24113_config = { | |
379 | .i2c_addr = 0x54, | |
380 | .xtal_khz = 10111, | |
381 | }; | |
382 | ||
eccd15aa | 383 | static int skystar2_rev28_attach(struct flexcop_device *fc, |
d66b94b4 PB |
384 | struct i2c_adapter *i2c) |
385 | { | |
eccd15aa TP |
386 | struct i2c_adapter *i2c_tuner; |
387 | ||
388 | fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config, | |
389 | i2c); | |
390 | if (!fc->fe) | |
391 | return 0; | |
392 | ||
1ebcad77 | 393 | i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe); |
eccd15aa TP |
394 | if (!i2c_tuner) |
395 | return 0; | |
d66b94b4 | 396 | |
eccd15aa TP |
397 | if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config, |
398 | i2c_tuner)) { | |
399 | err("CX24113 could NOT be attached"); | |
400 | return 0; | |
401 | } | |
402 | info("CX24113 successfully attached"); | |
403 | ||
404 | fc->fc_i2c_adap[2].no_base_addr = 1; | |
405 | if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, | |
48a8a03b | 406 | 0x08, 0, 0, false)) { |
eccd15aa TP |
407 | err("ISL6421 could NOT be attached"); |
408 | fc->fc_i2c_adap[2].no_base_addr = 0; | |
409 | return 0; | |
410 | } | |
411 | info("ISL6421 successfully attached"); | |
d66b94b4 PB |
412 | /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an |
413 | * IR-receiver (PIC16F818) - but the card has no input for that ??? */ | |
eccd15aa | 414 | return 1; |
d66b94b4 | 415 | } |
68b7f761 TP |
416 | #else |
417 | #define skystar2_rev28_attach NULL | |
d66b94b4 PB |
418 | #endif |
419 | ||
420 | /* AirStar DVB-T */ | |
6d67c971 | 421 | #if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL) |
d66b94b4 PB |
422 | static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe) |
423 | { | |
424 | static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d }; | |
425 | static u8 mt352_reset[] = { 0x50, 0x80 }; | |
426 | static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 }; | |
427 | static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 }; | |
2add87a9 JS |
428 | static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; |
429 | ||
430 | mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); | |
431 | udelay(2000); | |
432 | mt352_write(fe, mt352_reset, sizeof(mt352_reset)); | |
433 | mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); | |
2add87a9 JS |
434 | mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); |
435 | mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); | |
2add87a9 JS |
436 | return 0; |
437 | } | |
438 | ||
2add87a9 | 439 | static struct mt352_config samsung_tdtc9251dh0_config = { |
2add87a9 | 440 | .demod_address = 0x0f, |
55f51efd | 441 | .demod_init = samsung_tdtc9251dh0_demod_init, |
2add87a9 JS |
442 | }; |
443 | ||
eccd15aa | 444 | static int airstar_dvbt_attach(struct flexcop_device *fc, |
d66b94b4 PB |
445 | struct i2c_adapter *i2c) |
446 | { | |
447 | fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c); | |
6d67c971 TP |
448 | if (!fc->fe) |
449 | return 0; | |
450 | ||
451 | return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, | |
452 | DVB_PLL_SAMSUNG_TDTC9251DH0); | |
d66b94b4 | 453 | } |
68b7f761 TP |
454 | #else |
455 | #define airstar_dvbt_attach NULL | |
d66b94b4 PB |
456 | #endif |
457 | ||
458 | /* AirStar ATSC 1st generation */ | |
68b7f761 | 459 | #if FE_SUPPORTED(BCM3510) |
55f51efd JS |
460 | static struct bcm3510_config air2pc_atsc_first_gen_config = { |
461 | .demod_address = 0x0f, | |
462 | .request_firmware = flexcop_fe_request_firmware, | |
2add87a9 JS |
463 | }; |
464 | ||
eccd15aa | 465 | static int airstar_atsc1_attach(struct flexcop_device *fc, |
d66b94b4 | 466 | struct i2c_adapter *i2c) |
2add87a9 | 467 | { |
d66b94b4 | 468 | fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c); |
eccd15aa | 469 | return fc->fe != NULL; |
d66b94b4 | 470 | } |
68b7f761 TP |
471 | #else |
472 | #define airstar_atsc1_attach NULL | |
d66b94b4 | 473 | #endif |
2add87a9 | 474 | |
d66b94b4 | 475 | /* AirStar ATSC 2nd generation */ |
68b7f761 | 476 | #if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL) |
c5db7475 | 477 | static const struct nxt200x_config samsung_tbmv_config = { |
d66b94b4 PB |
478 | .demod_address = 0x0a, |
479 | }; | |
2add87a9 | 480 | |
eccd15aa | 481 | static int airstar_atsc2_attach(struct flexcop_device *fc, |
d66b94b4 PB |
482 | struct i2c_adapter *i2c) |
483 | { | |
484 | fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c); | |
eccd15aa TP |
485 | if (!fc->fe) |
486 | return 0; | |
487 | ||
488 | return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, | |
489 | DVB_PLL_SAMSUNG_TBMV); | |
2add87a9 | 490 | } |
68b7f761 TP |
491 | #else |
492 | #define airstar_atsc2_attach NULL | |
d66b94b4 | 493 | #endif |
2add87a9 | 494 | |
d66b94b4 | 495 | /* AirStar ATSC 3rd generation */ |
68b7f761 | 496 | #if FE_SUPPORTED(LGDT330X) |
d66b94b4 PB |
497 | static struct lgdt330x_config air2pc_atsc_hd5000_config = { |
498 | .demod_address = 0x59, | |
499 | .demod_chip = LGDT3303, | |
500 | .serial_mpeg = 0x04, | |
501 | .clock_polarity_flip = 1, | |
2add87a9 JS |
502 | }; |
503 | ||
eccd15aa | 504 | static int airstar_atsc3_attach(struct flexcop_device *fc, |
d66b94b4 PB |
505 | struct i2c_adapter *i2c) |
506 | { | |
507 | fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c); | |
eccd15aa TP |
508 | if (!fc->fe) |
509 | return 0; | |
510 | ||
511 | return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61, | |
512 | TUNER_LG_TDVS_H06XF); | |
d66b94b4 | 513 | } |
68b7f761 TP |
514 | #else |
515 | #define airstar_atsc3_attach NULL | |
d66b94b4 PB |
516 | #endif |
517 | ||
518 | /* CableStar2 DVB-C */ | |
7a6fbd83 | 519 | #if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL) |
dc27a169 AQ |
520 | static u8 alps_tdee4_stv0297_inittab[] = { |
521 | 0x80, 0x01, | |
522 | 0x80, 0x00, | |
523 | 0x81, 0x01, | |
524 | 0x81, 0x00, | |
9d85d776 AS |
525 | 0x00, 0x48, |
526 | 0x01, 0x58, | |
dc27a169 AQ |
527 | 0x03, 0x00, |
528 | 0x04, 0x00, | |
529 | 0x07, 0x00, | |
530 | 0x08, 0x00, | |
dc27a169 | 531 | 0x30, 0xff, |
9d85d776 | 532 | 0x31, 0x9d, |
dc27a169 AQ |
533 | 0x32, 0xff, |
534 | 0x33, 0x00, | |
9d85d776 AS |
535 | 0x34, 0x29, |
536 | 0x35, 0x55, | |
537 | 0x36, 0x80, | |
538 | 0x37, 0x6e, | |
539 | 0x38, 0x9c, | |
540 | 0x40, 0x1a, | |
541 | 0x41, 0xfe, | |
542 | 0x42, 0x33, | |
dc27a169 AQ |
543 | 0x43, 0x00, |
544 | 0x44, 0xff, | |
545 | 0x45, 0x00, | |
546 | 0x46, 0x00, | |
547 | 0x49, 0x04, | |
9d85d776 | 548 | 0x4a, 0x51, |
dc27a169 AQ |
549 | 0x4b, 0xf8, |
550 | 0x52, 0x30, | |
9d85d776 AS |
551 | 0x53, 0x06, |
552 | 0x59, 0x06, | |
553 | 0x5a, 0x5e, | |
554 | 0x5b, 0x04, | |
555 | 0x61, 0x49, | |
556 | 0x62, 0x0a, | |
dc27a169 | 557 | 0x70, 0xff, |
9d85d776 | 558 | 0x71, 0x04, |
dc27a169 AQ |
559 | 0x72, 0x00, |
560 | 0x73, 0x00, | |
561 | 0x74, 0x0c, | |
9d85d776 | 562 | 0x80, 0x20, |
dc27a169 | 563 | 0x81, 0x00, |
9d85d776 | 564 | 0x82, 0x30, |
dc27a169 AQ |
565 | 0x83, 0x00, |
566 | 0x84, 0x04, | |
9d85d776 AS |
567 | 0x85, 0x22, |
568 | 0x86, 0x08, | |
569 | 0x87, 0x1b, | |
570 | 0x88, 0x00, | |
dc27a169 | 571 | 0x89, 0x00, |
9d85d776 AS |
572 | 0x90, 0x00, |
573 | 0x91, 0x04, | |
574 | 0xa0, 0x86, | |
dc27a169 AQ |
575 | 0xa1, 0x00, |
576 | 0xa2, 0x00, | |
577 | 0xb0, 0x91, | |
578 | 0xb1, 0x0b, | |
9d85d776 AS |
579 | 0xc0, 0x5b, |
580 | 0xc1, 0x10, | |
dc27a169 | 581 | 0xc2, 0x12, |
9d85d776 | 582 | 0xd0, 0x02, |
dc27a169 AQ |
583 | 0xd1, 0x00, |
584 | 0xd2, 0x00, | |
585 | 0xd3, 0x00, | |
9d85d776 | 586 | 0xd4, 0x02, |
dc27a169 AQ |
587 | 0xd5, 0x00, |
588 | 0xde, 0x00, | |
9d85d776 | 589 | 0xdf, 0x01, |
dc27a169 AQ |
590 | 0xff, 0xff, |
591 | }; | |
592 | ||
2add87a9 JS |
593 | static struct stv0297_config alps_tdee4_stv0297_config = { |
594 | .demod_address = 0x1c, | |
dc27a169 | 595 | .inittab = alps_tdee4_stv0297_inittab, |
2add87a9 JS |
596 | }; |
597 | ||
eccd15aa | 598 | static int cablestar2_attach(struct flexcop_device *fc, |
d66b94b4 | 599 | struct i2c_adapter *i2c) |
2add87a9 | 600 | { |
11c6c7fb | 601 | fc->fc_i2c_adap[0].no_base_addr = 1; |
6394cf53 | 602 | fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c); |
7a6fbd83 TP |
603 | if (!fc->fe) |
604 | goto fail; | |
605 | ||
606 | /* This tuner doesn't use the stv0297's I2C gate, but instead the | |
607 | * tuner is connected to a different flexcop I2C adapter. */ | |
608 | if (fc->fe->ops.i2c_gate_ctrl) | |
609 | fc->fe->ops.i2c_gate_ctrl(fc->fe, 0); | |
610 | fc->fe->ops.i2c_gate_ctrl = NULL; | |
611 | ||
612 | if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, | |
613 | &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4)) | |
614 | goto fail; | |
615 | ||
eccd15aa | 616 | return 1; |
7a6fbd83 TP |
617 | |
618 | fail: | |
619 | /* Reset for next frontend to try */ | |
620 | fc->fc_i2c_adap[0].no_base_addr = 0; | |
621 | return 0; | |
d66b94b4 | 622 | } |
68b7f761 TP |
623 | #else |
624 | #define cablestar2_attach NULL | |
d66b94b4 PB |
625 | #endif |
626 | ||
5afc9a25 JD |
627 | /* SkyStar S2 PCI DVB-S/S2 card based on Conexant cx24120/cx24118 */ |
628 | #if FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421) | |
629 | static const struct cx24120_config skystar2_rev3_3_cx24120_config = { | |
630 | .i2c_addr = 0x55, | |
631 | .xtal_khz = 10111, | |
632 | .initial_mpeg_config = { 0xa1, 0x76, 0x07 }, | |
633 | .request_firmware = flexcop_fe_request_firmware, | |
f7a77ebf | 634 | .i2c_wr_max = 4, |
5afc9a25 JD |
635 | }; |
636 | ||
637 | static int skystarS2_rev33_attach(struct flexcop_device *fc, | |
638 | struct i2c_adapter *i2c) | |
639 | { | |
640 | fc->fe = dvb_attach(cx24120_attach, | |
cf4f8114 JD |
641 | &skystar2_rev3_3_cx24120_config, i2c); |
642 | if (!fc->fe) | |
5afc9a25 JD |
643 | return 0; |
644 | ||
645 | fc->dev_type = FC_SKYS2_REV33; | |
646 | fc->fc_i2c_adap[2].no_base_addr = 1; | |
cf4f8114 JD |
647 | if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, |
648 | 0x08, 0, 0, false)) { | |
5afc9a25 | 649 | err("ISL6421 could NOT be attached!"); |
cf4f8114 | 650 | fc->fc_i2c_adap[2].no_base_addr = 0; |
5afc9a25 JD |
651 | return 0; |
652 | } | |
653 | info("ISL6421 successfully attached."); | |
654 | ||
d3525b63 JD |
655 | if (fc->has_32_hw_pid_filter) |
656 | fc->skip_6_hw_pid_filter = 1; | |
657 | ||
5afc9a25 JD |
658 | return 1; |
659 | } | |
660 | #else | |
661 | #define skystarS2_rev33_attach NULL | |
662 | #endif | |
663 | ||
d66b94b4 PB |
664 | static struct { |
665 | flexcop_device_type_t type; | |
eccd15aa | 666 | int (*attach)(struct flexcop_device *, struct i2c_adapter *); |
d66b94b4 | 667 | } flexcop_frontends[] = { |
d66b94b4 | 668 | { FC_SKY_REV27, skystar2_rev27_attach }, |
d66b94b4 | 669 | { FC_SKY_REV28, skystar2_rev28_attach }, |
d66b94b4 | 670 | { FC_SKY_REV26, skystar2_rev26_attach }, |
d66b94b4 | 671 | { FC_AIR_DVBT, airstar_dvbt_attach }, |
d66b94b4 | 672 | { FC_AIR_ATSC2, airstar_atsc2_attach }, |
d66b94b4 | 673 | { FC_AIR_ATSC3, airstar_atsc3_attach }, |
d66b94b4 | 674 | { FC_AIR_ATSC1, airstar_atsc1_attach }, |
d66b94b4 | 675 | { FC_CABLE, cablestar2_attach }, |
d66b94b4 | 676 | { FC_SKY_REV23, skystar2_rev23_attach }, |
5afc9a25 | 677 | { FC_SKYS2_REV33, skystarS2_rev33_attach }, |
d66b94b4 | 678 | }; |
2add87a9 | 679 | |
d66b94b4 PB |
680 | /* try to figure out the frontend */ |
681 | int flexcop_frontend_init(struct flexcop_device *fc) | |
682 | { | |
683 | int i; | |
684 | for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) { | |
68b7f761 TP |
685 | if (!flexcop_frontends[i].attach) |
686 | continue; | |
d66b94b4 PB |
687 | /* type needs to be set before, because of some workarounds |
688 | * done based on the probed card type */ | |
689 | fc->dev_type = flexcop_frontends[i].type; | |
eccd15aa | 690 | if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap)) |
d66b94b4 | 691 | goto fe_found; |
eccd15aa TP |
692 | /* Clean up partially attached frontend */ |
693 | if (fc->fe) { | |
694 | dvb_frontend_detach(fc->fe); | |
695 | fc->fe = NULL; | |
696 | } | |
2add87a9 | 697 | } |
d66b94b4 | 698 | fc->dev_type = FC_UNK; |
6394cf53 PB |
699 | err("no frontend driver found for this B2C2/FlexCop adapter"); |
700 | return -ENODEV; | |
701 | ||
702 | fe_found: | |
703 | info("found '%s' .", fc->fe->ops.info.name); | |
704 | if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { | |
705 | err("frontend registration failed!"); | |
eccd15aa | 706 | dvb_frontend_detach(fc->fe); |
6394cf53 PB |
707 | fc->fe = NULL; |
708 | return -EINVAL; | |
2add87a9 JS |
709 | } |
710 | fc->init_state |= FC_STATE_FE_INIT; | |
711 | return 0; | |
712 | } | |
713 | ||
714 | void flexcop_frontend_exit(struct flexcop_device *fc) | |
715 | { | |
2bfe031d | 716 | if (fc->init_state & FC_STATE_FE_INIT) { |
2add87a9 | 717 | dvb_unregister_frontend(fc->fe); |
f52a838b | 718 | dvb_frontend_detach(fc->fe); |
2bfe031d | 719 | } |
2add87a9 JS |
720 | fc->init_state &= ~FC_STATE_FE_INIT; |
721 | } |