blob: 3f485bf131212e755c806672d724b0e19f6acb44 [file] [log] [blame]
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07001/*
Patrick Boettcherd66b94b2009-05-20 05:08:26 -03002 * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
3 * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
4 * see flexcop.c for copyright information
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07005 */
Michael Krufky827855d2008-04-22 14:46:16 -03006#include <media/tuner.h>
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07007#include "flexcop.h"
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07008#include "mt312.h"
Patrick Boettcherd66b94b2009-05-20 05:08:26 -03009#include "stv0299.h"
Patrick Boettcherca19aaa2008-04-13 15:49:22 -030010#include "s5h1420.h"
11#include "itd1000.h"
Patrick Boettcherc9dd82c2008-03-29 21:28:07 -030012#include "cx24113.h"
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030013#include "cx24123.h"
Patrick Boettcherc9dd82c2008-03-29 21:28:07 -030014#include "isl6421.h"
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030015#include "mt352.h"
16#include "bcm3510.h"
17#include "nxt200x.h"
18#include "dvb-pll.h"
19#include "lgdt330x.h"
20#include "tuner-simple.h"
21#include "stv0297.h"
Patrick Boettcherc9dd82c2008-03-29 21:28:07 -030022
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070023/* lnb control */
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030024#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070025static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
26{
27 struct flexcop_device *fc = fe->dvb->priv;
28 flexcop_ibi_value v;
29 deb_tuner("polarity/voltage = %u\n", voltage);
30
31 v = fc->read_ibi_reg(fc, misc_204);
32 switch (voltage) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030033 case SEC_VOLTAGE_OFF:
34 v.misc_204.ACPI1_sig = 1;
35 break;
36 case SEC_VOLTAGE_13:
37 v.misc_204.ACPI1_sig = 0;
38 v.misc_204.LNB_L_H_sig = 0;
39 break;
40 case SEC_VOLTAGE_18:
41 v.misc_204.ACPI1_sig = 0;
42 v.misc_204.LNB_L_H_sig = 1;
43 break;
44 default:
45 err("unknown SEC_VOLTAGE value");
46 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070047 }
48 return fc->write_ibi_reg(fc, misc_204, v);
49}
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030050#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070051
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030052#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
53 || defined(CONFIG_DVB_MT312_MODULE)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070054static int flexcop_sleep(struct dvb_frontend* fe)
55{
56 struct flexcop_device *fc = fe->dvb->priv;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070057 if (fc->fe_sleep)
58 return fc->fe_sleep(fe);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070059 return 0;
60}
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030061#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070062
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030063/* SkyStar2 DVB-S rev 2.3 */
64#if defined(CONFIG_DVB_MT312_MODULE)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070065static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
66{
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030067/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070068 struct flexcop_device *fc = fe->dvb->priv;
69 flexcop_ibi_value v;
70 u16 ax;
71 v.raw = 0;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070072 deb_tuner("tone = %u\n",tone);
73
74 switch (tone) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030075 case SEC_TONE_ON:
76 ax = 0x01ff;
77 break;
78 case SEC_TONE_OFF:
79 ax = 0;
80 break;
81 default:
82 err("unknown SEC_TONE value");
83 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070084 }
85
86 v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
Johannes Stezenbach958706c2005-05-16 21:54:19 -070087 v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
88 v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070089 return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
90}
91
92static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
93{
94 flexcop_set_tone(fe, SEC_TONE_ON);
95 udelay(data ? 500 : 1000);
96 flexcop_set_tone(fe, SEC_TONE_OFF);
97 udelay(data ? 1000 : 500);
98}
99
100static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
101{
102 int i, par = 1, d;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700103 for (i = 7; i >= 0; i--) {
104 d = (data >> i) & 1;
105 par ^= d;
106 flexcop_diseqc_send_bit(fe, d);
107 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700108 flexcop_diseqc_send_bit(fe, par);
109}
110
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300111static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
112 int len, u8 *msg, unsigned long burst)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700113{
114 int i;
115
116 flexcop_set_tone(fe, SEC_TONE_OFF);
117 mdelay(16);
118
119 for (i = 0; i < len; i++)
120 flexcop_diseqc_send_byte(fe,msg[i]);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700121 mdelay(16);
122
123 if (burst != -1) {
124 if (burst)
125 flexcop_diseqc_send_byte(fe, 0xff);
126 else {
127 flexcop_set_tone(fe, SEC_TONE_ON);
Thierry MERLEc4e3fd92008-09-01 17:32:10 -0300128 mdelay(12);
129 udelay(500);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700130 flexcop_set_tone(fe, SEC_TONE_OFF);
131 }
132 msleep(20);
133 }
134 return 0;
135}
136
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300137static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
138 struct dvb_diseqc_master_cmd *cmd)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700139{
140 return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
141}
142
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300143static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
144 fe_sec_mini_cmd_t minicmd)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700145{
146 return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
147}
148
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300149static struct mt312_config skystar23_samsung_tbdu18132_config = {
150 .demod_address = 0x0e,
151};
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700152
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300153static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
154 struct dvb_frontend_parameters *params)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700155{
156 u8 buf[4];
157 u32 div;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300158 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
159 .len = sizeof(buf) };
Andrew de Quincey56e03142006-04-18 17:47:12 -0300160 struct flexcop_device *fc = fe->dvb->priv;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700161 div = (params->frequency + (125/2)) / 125;
162
163 buf[0] = (div >> 8) & 0x7f;
164 buf[1] = (div >> 0) & 0xff;
165 buf[2] = 0x84 | ((div >> 10) & 0x60);
166 buf[3] = 0x80;
167
168 if (params->frequency < 1550000)
169 buf[3] |= 0x02;
170
Patrick Boettcherdea74862006-05-14 05:01:31 -0300171 if (fe->ops.i2c_gate_ctrl)
172 fe->ops.i2c_gate_ctrl(fe, 1);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300173 if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700174 return -EIO;
175 return 0;
176}
177
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300178static void skystar2_rev23_attach(struct flexcop_device *fc,
179 struct i2c_adapter *i2c)
180{
181 fc->fe = dvb_attach(mt312_attach,
182 &skystar23_samsung_tbdu18132_config, i2c);
183 if (fc->fe != NULL) {
184 struct dvb_frontend_ops *ops = &fc->fe->ops;
185 ops->tuner_ops.set_params \
186 = skystar23_samsung_tbdu18132_tuner_set_params;
187 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
188 ops->diseqc_send_burst = flexcop_diseqc_send_burst;
189 ops->set_tone = flexcop_set_tone;
190 ops->set_voltage = flexcop_set_voltage;
191 fc->fe_sleep = ops->sleep;
192 ops->sleep = flexcop_sleep;
193 fc->dev_type = FC_SKY_REV23;
194 }
195}
196#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700197
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300198/* SkyStar2 DVB-S rev 2.6 */
199#if defined(CONFIG_DVB_STV0299_MODULE)
200static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
201 u32 srate, u32 ratio)
202{
203 u8 aclk = 0;
204 u8 bclk = 0;
205
206 if (srate < 1500000) {
207 aclk = 0xb7; bclk = 0x47;
208 } else if (srate < 3000000) {
209 aclk = 0xb7; bclk = 0x4b;
210 } else if (srate < 7000000) {
211 aclk = 0xb7; bclk = 0x4f;
212 } else if (srate < 14000000) {
213 aclk = 0xb7; bclk = 0x53;
214 } else if (srate < 30000000) {
215 aclk = 0xb6; bclk = 0x53;
216 } else if (srate < 45000000) {
217 aclk = 0xb4; bclk = 0x51;
218 }
219
220 stv0299_writereg(fe, 0x13, aclk);
221 stv0299_writereg(fe, 0x14, bclk);
222 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
223 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
224 stv0299_writereg(fe, 0x21, ratio & 0xf0);
225 return 0;
226}
227
228static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
229 struct dvb_frontend_parameters *params)
230{
231 u8 buf[4];
232 u32 div;
233 struct i2c_msg msg = {
234 .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
235 struct flexcop_device *fc = fe->dvb->priv;
236 div = params->frequency / 125;
237
238 buf[0] = (div >> 8) & 0x7f;
239 buf[1] = div & 0xff;
240 buf[2] = 0x84; /* 0xC4 */
241 buf[3] = 0x08;
242
243 if (params->frequency < 1500000)
244 buf[3] |= 0x10;
245
246 if (fe->ops.i2c_gate_ctrl)
247 fe->ops.i2c_gate_ctrl(fe, 1);
248 if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
249 return -EIO;
250 return 0;
251}
252
253static u8 samsung_tbmu24112_inittab[] = {
254 0x01, 0x15,
255 0x02, 0x30,
256 0x03, 0x00,
257 0x04, 0x7D,
258 0x05, 0x35,
259 0x06, 0x02,
260 0x07, 0x00,
261 0x08, 0xC3,
262 0x0C, 0x00,
263 0x0D, 0x81,
264 0x0E, 0x23,
265 0x0F, 0x12,
266 0x10, 0x7E,
267 0x11, 0x84,
268 0x12, 0xB9,
269 0x13, 0x88,
270 0x14, 0x89,
271 0x15, 0xC9,
272 0x16, 0x00,
273 0x17, 0x5C,
274 0x18, 0x00,
275 0x19, 0x00,
276 0x1A, 0x00,
277 0x1C, 0x00,
278 0x1D, 0x00,
279 0x1E, 0x00,
280 0x1F, 0x3A,
281 0x20, 0x2E,
282 0x21, 0x80,
283 0x22, 0xFF,
284 0x23, 0xC1,
285 0x28, 0x00,
286 0x29, 0x1E,
287 0x2A, 0x14,
288 0x2B, 0x0F,
289 0x2C, 0x09,
290 0x2D, 0x05,
291 0x31, 0x1F,
292 0x32, 0x19,
293 0x33, 0xFE,
294 0x34, 0x93,
295 0xff, 0xff,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700296};
297
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300298static struct stv0299_config samsung_tbmu24112_config = {
299 .demod_address = 0x68,
300 .inittab = samsung_tbmu24112_inittab,
301 .mclk = 88000000UL,
302 .invert = 0,
303 .skip_reinit = 0,
304 .lock_output = STV0299_LOCKOUTPUT_LK,
305 .volt13_op0_op1 = STV0299_VOLT13_OP1,
306 .min_delay_ms = 100,
307 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
308};
309
310static void skystar2_rev26_attach(struct flexcop_device *fc,
311 struct i2c_adapter *i2c)
312{
313 fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
314 if (fc->fe != NULL) {
315 struct dvb_frontend_ops *ops = &fc->fe->ops;
316 ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
317 ops->set_voltage = flexcop_set_voltage;
318 fc->fe_sleep = ops->sleep;
319 ops->sleep = flexcop_sleep;
320 }
321}
322#endif
323
324/* SkyStar2 DVB-S rev 2.7 */
325#if defined(CONFIG_DVB_S5H1420_MODULE)
326static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
327 .demod_address = 0x53,
328 .invert = 1,
329 .repeated_start_workaround = 1,
330 .serial_mpeg = 1,
331};
332
333static struct itd1000_config skystar2_rev2_7_itd1000_config = {
334 .i2c_address = 0x61,
335};
336
337static void skystar2_rev27_attach(struct flexcop_device *fc,
338 struct i2c_adapter *i2c)
339{
340 /* enable no_base_addr - no repeated start when reading */
341 fc->fc_i2c_adap[0].no_base_addr = 1;
342 fc->fe = dvb_attach(s5h1420_attach,
343 &skystar2_rev2_7_s5h1420_config, i2c);
344 if (fc->fe != NULL) {
345 flexcop_ibi_value r108;
346 struct i2c_adapter *i2c_tuner \
347 = s5h1420_get_tuner_i2c_adapter(fc->fe);
348 struct dvb_frontend_ops *ops = &fc->fe->ops;
349
350 fc->fe_sleep = ops->sleep;
351 ops->sleep = flexcop_sleep;
352
353 /* enable no_base_addr - no repeated start when reading */
354 fc->fc_i2c_adap[2].no_base_addr = 1;
355 if (dvb_attach(isl6421_attach, fc->fe,
356 &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
357 err("ISL6421 could NOT be attached");
358 else
359 info("ISL6421 successfully attached");
360
361 /* the ITD1000 requires a lower i2c clock - is it a problem ? */
362 r108.raw = 0x00000506;
363 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
364 if (i2c_tuner) {
365 if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
366 &skystar2_rev2_7_itd1000_config) == NULL)
367 err("ITD1000 could NOT be attached");
368 else
369 info("ITD1000 successfully attached");
370 }
371 } else
372 fc->fc_i2c_adap[0].no_base_addr = 0;
373 /* for the next devices we need it again */
374}
375#endif
376
377/* SkyStar2 rev 2.8 */
378#if defined(CONFIG_DVB_CX24123_MODULE)
379static struct cx24123_config skystar2_rev2_8_cx24123_config = {
380 .demod_address = 0x55,
381 .dont_use_pll = 1,
382 .agc_callback = cx24113_agc_callback,
383};
384
385static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
386 .i2c_addr = 0x54,
387 .xtal_khz = 10111,
388};
389
390static void skystar2_rev28_attach(struct flexcop_device *fc,
391 struct i2c_adapter *i2c)
392{
393 fc->fe = dvb_attach(cx24123_attach,
394 &skystar2_rev2_8_cx24123_config, i2c);
395 if (fc->fe != NULL) {
396 struct i2c_adapter *i2c_tuner \
397 = cx24123_get_tuner_i2c_adapter(fc->fe);
398 if (i2c_tuner != NULL) {
399 if (dvb_attach(cx24113_attach, fc->fe,
400 &skystar2_rev2_8_cx24113_config,
401 i2c_tuner) == NULL)
402 err("CX24113 could NOT be attached");
403 else
404 info("CX24113 successfully attached");
405 }
406
407 fc->fc_i2c_adap[2].no_base_addr = 1;
408 if (dvb_attach(isl6421_attach, fc->fe,
409 &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
410 err("ISL6421 could NOT be attached");
411 else
412 info("ISL6421 successfully attached");
413 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
414 * IR-receiver (PIC16F818) - but the card has no input for that ??? */
415 }
416}
417#endif
418
419/* AirStar DVB-T */
420#if defined(CONFIG_DVB_MT352_MODULE)
421static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
422{
423 static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
424 static u8 mt352_reset[] = { 0x50, 0x80 };
425 static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
426 static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
427 static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
428
429 mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
430 udelay(2000);
431 mt352_write(fe, mt352_reset, sizeof(mt352_reset));
432 mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
433 mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
434 mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
435 return 0;
436}
437
438static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
439 struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
440{
441 u32 div;
442 unsigned char bs = 0;
443
444 if (buf_len < 5)
445 return -EINVAL;
446
447#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
448 div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
449 if (params->frequency >= 48000000 && params->frequency <= 154000000) \
450 bs = 0x09;
451 if (params->frequency >= 161000000 && params->frequency <= 439000000) \
452 bs = 0x0a;
453 if (params->frequency >= 447000000 && params->frequency <= 863000000) \
454 bs = 0x08;
455
456 pllbuf[0] = 0x61;
457 pllbuf[1] = div >> 8;
458 pllbuf[2] = div & 0xff;
459 pllbuf[3] = 0xcc;
460 pllbuf[4] = bs;
461 return 5;
462}
463
464static struct mt352_config samsung_tdtc9251dh0_config = {
465 .demod_address = 0x0f,
466 .demod_init = samsung_tdtc9251dh0_demod_init,
467};
468
469static void airstar_dvbt_attach(struct flexcop_device *fc,
470 struct i2c_adapter *i2c)
471{
472 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
473 if (fc->fe != NULL)
474 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
475}
476#endif
477
478/* AirStar ATSC 1st generation */
479#if defined(CONFIG_DVB_BCM3510_MODULE)
480static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
481 const struct firmware **fw, char* name)
482{
483 struct flexcop_device *fc = fe->dvb->priv;
484 return request_firmware(fw, name, fc->dev);
485}
486
487static struct bcm3510_config air2pc_atsc_first_gen_config = {
488 .demod_address = 0x0f,
489 .request_firmware = flexcop_fe_request_firmware,
490};
491
492static void airstar_atsc1_attach(struct flexcop_device *fc,
493 struct i2c_adapter *i2c)
494{
495 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
496}
497#endif
498
499/* AirStar ATSC 2nd generation */
500#if defined(CONFIG_DVB_NXT200X_MODULE)
501static struct nxt200x_config samsung_tbmv_config = {
502 .demod_address = 0x0a,
503};
504
505static void airstar_atsc2_attach(struct flexcop_device *fc,
506 struct i2c_adapter *i2c)
507{
508 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
509 if (fc->fe != NULL)
510 dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
511 DVB_PLL_SAMSUNG_TBMV);
512}
513#endif
514
515/* AirStar ATSC 3rd generation */
516#if defined(CONFIG_DVB_LGDT330X_MODULE)
517static struct lgdt330x_config air2pc_atsc_hd5000_config = {
518 .demod_address = 0x59,
519 .demod_chip = LGDT3303,
520 .serial_mpeg = 0x04,
521 .clock_polarity_flip = 1,
522};
523
524static void airstar_atsc3_attach(struct flexcop_device *fc,
525 struct i2c_adapter *i2c)
526{
527 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
528 if (fc->fe != NULL) {
529 dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
530 TUNER_LG_TDVS_H06XF);
531 }
532}
533#endif
534
535/* CableStar2 DVB-C */
536#if defined(CONFIG_DVB_STV0297_MODULE)
Adrian Bunkdd00b1e2006-05-29 12:31:44 -0300537static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300538 struct dvb_frontend_parameters *fep)
Andrew de Quincey56e03142006-04-18 17:47:12 -0300539{
540 struct flexcop_device *fc = fe->dvb->priv;
541 u8 buf[4];
542 u16 div;
543 int ret;
544
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300545/* 62.5 kHz * 10 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300546#define REF_FREQ 625
547#define FREQ_OFFSET 36125
548
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300549 div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
550/* 4 MHz = 4000 KHz */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300551
552 buf[0] = (u8)( div >> 8) & 0x7f;
553 buf[1] = (u8) div & 0xff;
554
555/* F(osc) = N * Reference Freq. (62.5 kHz)
556 * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
557 * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
558 * byte 4 : 1 * * AGD R3 R2 R1 R0
559 * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
560 * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
561 buf[2] = 0x95;
562
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300563/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
564 * 47 - 153 0 * 0 0 0 0 0 1 0x01
565 * 153 - 430 0 * 0 0 0 0 1 0 0x02
566 * 430 - 822 0 * 0 0 1 0 0 0 0x08
567 * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300568
569 if (fep->frequency <= 153000000) buf[3] = 0x01;
570 else if (fep->frequency <= 430000000) buf[3] = 0x02;
571 else if (fep->frequency <= 822000000) buf[3] = 0x08;
572 else buf[3] = 0x88;
573
Patrick Boettcherdea74862006-05-14 05:01:31 -0300574 if (fe->ops.i2c_gate_ctrl)
Antti Seppälä9d85d772006-12-20 11:10:35 -0300575 fe->ops.i2c_gate_ctrl(fe, 0);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300576 deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
577 buf[0], buf[1], buf[2], buf[3]);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300578 ret = fc->i2c_request(&fc->fc_i2c_adap[2],
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300579 FC_WRITE, 0x61, buf[0], &buf[1], 3);
Andrew de Quincey56e03142006-04-18 17:47:12 -0300580 deb_tuner("tuner write returned: %d\n",ret);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300581 return ret;
Andrew de Quincey56e03142006-04-18 17:47:12 -0300582}
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700583
584static u8 alps_tdee4_stv0297_inittab[] = {
585 0x80, 0x01,
586 0x80, 0x00,
587 0x81, 0x01,
588 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300589 0x00, 0x48,
590 0x01, 0x58,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700591 0x03, 0x00,
592 0x04, 0x00,
593 0x07, 0x00,
594 0x08, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700595 0x30, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300596 0x31, 0x9d,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700597 0x32, 0xff,
598 0x33, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300599 0x34, 0x29,
600 0x35, 0x55,
601 0x36, 0x80,
602 0x37, 0x6e,
603 0x38, 0x9c,
604 0x40, 0x1a,
605 0x41, 0xfe,
606 0x42, 0x33,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700607 0x43, 0x00,
608 0x44, 0xff,
609 0x45, 0x00,
610 0x46, 0x00,
611 0x49, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300612 0x4a, 0x51,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700613 0x4b, 0xf8,
614 0x52, 0x30,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300615 0x53, 0x06,
616 0x59, 0x06,
617 0x5a, 0x5e,
618 0x5b, 0x04,
619 0x61, 0x49,
620 0x62, 0x0a,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700621 0x70, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300622 0x71, 0x04,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700623 0x72, 0x00,
624 0x73, 0x00,
625 0x74, 0x0c,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300626 0x80, 0x20,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700627 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300628 0x82, 0x30,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700629 0x83, 0x00,
630 0x84, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300631 0x85, 0x22,
632 0x86, 0x08,
633 0x87, 0x1b,
634 0x88, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700635 0x89, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300636 0x90, 0x00,
637 0x91, 0x04,
638 0xa0, 0x86,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700639 0xa1, 0x00,
640 0xa2, 0x00,
641 0xb0, 0x91,
642 0xb1, 0x0b,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300643 0xc0, 0x5b,
644 0xc1, 0x10,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700645 0xc2, 0x12,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300646 0xd0, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700647 0xd1, 0x00,
648 0xd2, 0x00,
649 0xd3, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300650 0xd4, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700651 0xd5, 0x00,
652 0xde, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300653 0xdf, 0x01,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700654 0xff, 0xff,
655};
656
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700657static struct stv0297_config alps_tdee4_stv0297_config = {
658 .demod_address = 0x1c,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700659 .inittab = alps_tdee4_stv0297_inittab,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700660};
661
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300662static void cablestar2_attach(struct flexcop_device *fc,
663 struct i2c_adapter *i2c)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700664{
Antti Seppälä11c6c7f2008-12-01 06:59:37 -0300665 fc->fc_i2c_adap[0].no_base_addr = 1;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300666 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300667 if (fc->fe != NULL)
668 fc->fe->ops.tuner_ops.set_params \
669 = alps_tdee4_stv0297_tuner_set_params;
670 else
671 fc->fc_i2c_adap[0].no_base_addr = 0;
672}
673#endif
674
675static struct {
676 flexcop_device_type_t type;
677 void (*attach)(struct flexcop_device *, struct i2c_adapter *);
678} flexcop_frontends[] = {
679#if defined(CONFIG_DVB_S5H1420_MODULE)
680 { FC_SKY_REV27, skystar2_rev27_attach },
681#endif
682#if defined(CONFIG_DVB_CX24123_MODULE)
683 { FC_SKY_REV28, skystar2_rev28_attach },
684#endif
685#if defined(CONFIG_DVB_STV0299_MODULE)
686 { FC_SKY_REV26, skystar2_rev26_attach },
687#endif
688#if defined(CONFIG_DVB_MT352_MODULE)
689 { FC_AIR_DVBT, airstar_dvbt_attach },
690#endif
691#if defined(CONFIG_DVB_NXT200X_MODULE)
692 { FC_AIR_ATSC2, airstar_atsc2_attach },
693#endif
694#if defined(CONFIG_DVB_LGDT330X_MODULE)
695 { FC_AIR_ATSC3, airstar_atsc3_attach },
696#endif
697#if defined(CONFIG_DVB_BCM3510_MODULE)
698 { FC_AIR_ATSC1, airstar_atsc1_attach },
699#endif
700#if defined(CONFIG_DVB_STV0297_MODULE)
701 { FC_CABLE, cablestar2_attach },
702#endif
703#if defined(CONFIG_DVB_MT312_MODULE)
704 { FC_SKY_REV23, skystar2_rev23_attach },
705#endif
706};
707
708/* try to figure out the frontend */
709int flexcop_frontend_init(struct flexcop_device *fc)
710{
711 int i;
712 for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
713 /* type needs to be set before, because of some workarounds
714 * done based on the probed card type */
715 fc->dev_type = flexcop_frontends[i].type;
716 flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap);
717 if (fc->fe != NULL)
718 goto fe_found;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300719 }
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300720 fc->dev_type = FC_UNK;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300721 err("no frontend driver found for this B2C2/FlexCop adapter");
722 return -ENODEV;
723
724fe_found:
725 info("found '%s' .", fc->fe->ops.info.name);
726 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300727 struct dvb_frontend_ops *ops = &fc->fe->ops;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300728 err("frontend registration failed!");
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300729 if (ops->release != NULL)
730 ops->release(fc->fe);
731 fc->fe = NULL;
732 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700733 }
734 fc->init_state |= FC_STATE_FE_INIT;
735 return 0;
736}
737
738void flexcop_frontend_exit(struct flexcop_device *fc)
739{
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300740 if (fc->init_state & FC_STATE_FE_INIT) {
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700741 dvb_unregister_frontend(fc->fe);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -0300742 dvb_frontend_detach(fc->fe);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300743 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700744 fc->init_state &= ~FC_STATE_FE_INIT;
745}