blob: a35330315f6597f4019026ca11649f0584bec1c3 [file] [log] [blame]
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07001/*
2 * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
3 *
4 * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
5 *
6 * see flexcop.c for copyright information.
7 */
8#include "flexcop.h"
9
10#include "stv0299.h"
11#include "mt352.h"
12#include "nxt2002.h"
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -070013#include "bcm3510.h"
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070014#include "stv0297.h"
15#include "mt312.h"
Michael Krufkyc0b11b92005-11-08 21:35:32 -080016#include "lgdt330x.h"
17#include "dvb-pll.h"
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070018
19/* lnb control */
20
21static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
22{
23 struct flexcop_device *fc = fe->dvb->priv;
24 flexcop_ibi_value v;
25 deb_tuner("polarity/voltage = %u\n", voltage);
26
27 v = fc->read_ibi_reg(fc, misc_204);
28 switch (voltage) {
29 case SEC_VOLTAGE_OFF:
30 v.misc_204.ACPI1_sig = 1;
31 break;
32 case SEC_VOLTAGE_13:
33 v.misc_204.ACPI1_sig = 0;
34 v.misc_204.LNB_L_H_sig = 0;
35 break;
36 case SEC_VOLTAGE_18:
37 v.misc_204.ACPI1_sig = 0;
38 v.misc_204.LNB_L_H_sig = 1;
39 break;
40 default:
41 err("unknown SEC_VOLTAGE value");
42 return -EINVAL;
43 }
44 return fc->write_ibi_reg(fc, misc_204, v);
45}
46
47static int flexcop_sleep(struct dvb_frontend* fe)
48{
49 struct flexcop_device *fc = fe->dvb->priv;
50/* flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
51
52 if (fc->fe_sleep)
53 return fc->fe_sleep(fe);
54
55/* v.misc_204.ACPI3_sig = 1;
56 fc->write_ibi_reg(fc,misc_204,v);*/
57
58 return 0;
59}
60
61static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
62{
63 /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
64 struct flexcop_device *fc = fe->dvb->priv;
65 flexcop_ibi_value v;
66 u16 ax;
67 v.raw = 0;
68
69 deb_tuner("tone = %u\n",tone);
70
71 switch (tone) {
72 case SEC_TONE_ON:
73 ax = 0x01ff;
74 break;
75 case SEC_TONE_OFF:
76 ax = 0;
77 break;
78 default:
79 err("unknown SEC_TONE value");
80 return -EINVAL;
81 }
82
83 v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
84
Johannes Stezenbach958706c2005-05-16 21:54:19 -070085 v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
86 v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070087
88 return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
89}
90
91static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
92{
93 flexcop_set_tone(fe, SEC_TONE_ON);
94 udelay(data ? 500 : 1000);
95 flexcop_set_tone(fe, SEC_TONE_OFF);
96 udelay(data ? 1000 : 500);
97}
98
99static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
100{
101 int i, par = 1, d;
102
103 for (i = 7; i >= 0; i--) {
104 d = (data >> i) & 1;
105 par ^= d;
106 flexcop_diseqc_send_bit(fe, d);
107 }
108
109 flexcop_diseqc_send_bit(fe, par);
110}
111
112static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
113{
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]);
121
122 mdelay(16);
123
124 if (burst != -1) {
125 if (burst)
126 flexcop_diseqc_send_byte(fe, 0xff);
127 else {
128 flexcop_set_tone(fe, SEC_TONE_ON);
129 udelay(12500);
130 flexcop_set_tone(fe, SEC_TONE_OFF);
131 }
132 msleep(20);
133 }
134 return 0;
135}
136
137static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
138{
139 return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
140}
141
142static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
143{
144 return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
145}
146
147/* dvb-s stv0299 */
148static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
149{
150 u8 aclk = 0;
151 u8 bclk = 0;
152
153 if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
154 else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
155 else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
156 else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
157 else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
158 else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
159
160 stv0299_writereg (fe, 0x13, aclk);
161 stv0299_writereg (fe, 0x14, bclk);
162 stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
163 stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff);
164 stv0299_writereg (fe, 0x21, (ratio ) & 0xf0);
165
166 return 0;
167}
168
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700169static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700170{
171 u8 buf[4];
172 u32 div;
173 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700174
175 div = params->frequency / 125;
176
177 buf[0] = (div >> 8) & 0x7f;
178 buf[1] = div & 0xff;
179 buf[2] = 0x84; /* 0xC4 */
180 buf[3] = 0x08;
181
182 if (params->frequency < 1500000) buf[3] |= 0x10;
183
Andreas Oberrittercfbfce12005-09-09 13:02:30 -0700184 if (i2c_transfer(i2c, &msg, 1) != 1)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700185 return -EIO;
186 return 0;
187}
188
189static u8 samsung_tbmu24112_inittab[] = {
190 0x01, 0x15,
191 0x02, 0x30,
192 0x03, 0x00,
193 0x04, 0x7D,
194 0x05, 0x35,
195 0x06, 0x02,
196 0x07, 0x00,
197 0x08, 0xC3,
198 0x0C, 0x00,
199 0x0D, 0x81,
200 0x0E, 0x23,
201 0x0F, 0x12,
202 0x10, 0x7E,
203 0x11, 0x84,
204 0x12, 0xB9,
205 0x13, 0x88,
206 0x14, 0x89,
207 0x15, 0xC9,
208 0x16, 0x00,
209 0x17, 0x5C,
210 0x18, 0x00,
211 0x19, 0x00,
212 0x1A, 0x00,
213 0x1C, 0x00,
214 0x1D, 0x00,
215 0x1E, 0x00,
216 0x1F, 0x3A,
217 0x20, 0x2E,
218 0x21, 0x80,
219 0x22, 0xFF,
220 0x23, 0xC1,
221 0x28, 0x00,
222 0x29, 0x1E,
223 0x2A, 0x14,
224 0x2B, 0x0F,
225 0x2C, 0x09,
226 0x2D, 0x05,
227 0x31, 0x1F,
228 0x32, 0x19,
229 0x33, 0xFE,
230 0x34, 0x93,
231 0xff, 0xff,
232};
233
234static struct stv0299_config samsung_tbmu24112_config = {
235 .demod_address = 0x68,
236 .inittab = samsung_tbmu24112_inittab,
237 .mclk = 88000000UL,
238 .invert = 0,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700239 .skip_reinit = 0,
240 .lock_output = STV0229_LOCKOUTPUT_LK,
241 .volt13_op0_op1 = STV0299_VOLT13_OP1,
242 .min_delay_ms = 100,
243 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
244 .pll_set = samsung_tbmu24112_pll_set,
245};
246
247/* dvb-t mt352 */
248static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
249{
250 static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
251 static u8 mt352_reset [] = { 0x50, 0x80 };
252 static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
253 static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
254 static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
255
256 mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
257 udelay(2000);
258 mt352_write(fe, mt352_reset, sizeof(mt352_reset));
259 mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
260
261 mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
262 mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
263
264 return 0;
265}
266
267static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
268{
269 u32 div;
270 unsigned char bs = 0;
271
272 #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
273 div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
274
275 if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
276 if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
277 if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
278
279 pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
280 pllbuf[1] = div >> 8;
281 pllbuf[2] = div & 0xff;
282 pllbuf[3] = 0xcc;
283 pllbuf[4] = bs;
284
285 return 0;
286}
287
288static struct mt352_config samsung_tdtc9251dh0_config = {
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700289 .demod_address = 0x0f,
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700290 .demod_init = samsung_tdtc9251dh0_demod_init,
291 .pll_set = samsung_tdtc9251dh0_pll_set,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700292};
293
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700294static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700295{
296 struct flexcop_device *fc = fe->dvb->priv;
297 return request_firmware(fw, name, fc->dev);
298}
299
Michael Krufkyc0b11b92005-11-08 21:35:32 -0800300static int lgdt3303_pll_set(struct dvb_frontend* fe,
301 struct dvb_frontend_parameters* params)
302{
303 struct flexcop_device *fc = fe->dvb->priv;
304 u8 buf[4];
305 struct i2c_msg msg =
306 { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 };
307 int err;
308
309 dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0);
310 dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n",
311 __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]);
312 if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
313 printk(KERN_WARNING "lgdt3303: %s error "
314 "(addr %02x <- %02x, err = %i)\n",
315 __FUNCTION__, buf[0], buf[1], err);
316 if (err < 0)
317 return err;
318 else
319 return -EREMOTEIO;
320 }
321
322 buf[0] = 0x86 | 0x18;
323 buf[1] = 0x50;
324 msg.len = 2;
325 if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) {
326 printk(KERN_WARNING "lgdt3303: %s error "
327 "(addr %02x <- %02x, err = %i)\n",
328 __FUNCTION__, buf[0], buf[1], err);
329 if (err < 0)
330 return err;
331 else
332 return -EREMOTEIO;
333 }
334
335 return 0;
336}
337
338static struct lgdt330x_config air2pc_atsc_hd5000_config = {
339 .demod_address = 0x59,
340 .demod_chip = LGDT3303,
341 .serial_mpeg = 0x04,
342 .pll_set = lgdt3303_pll_set,
343 .clock_polarity_flip = 1,
344};
345
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700346static struct nxt2002_config samsung_tbmv_config = {
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700347 .demod_address = 0x0a,
348 .request_firmware = flexcop_fe_request_firmware,
349};
350
351static struct bcm3510_config air2pc_atsc_first_gen_config = {
352 .demod_address = 0x0f,
353 .request_firmware = flexcop_fe_request_firmware,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700354};
355
356static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
357{
358 u8 buf[4];
359 u32 div;
360 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
361 struct flexcop_device *fc = fe->dvb->priv;
362
363 div = (params->frequency + (125/2)) / 125;
364
365 buf[0] = (div >> 8) & 0x7f;
366 buf[1] = (div >> 0) & 0xff;
367 buf[2] = 0x84 | ((div >> 10) & 0x60);
368 buf[3] = 0x80;
369
370 if (params->frequency < 1550000)
371 buf[3] |= 0x02;
372
373 if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
374 return -EIO;
375 return 0;
376}
377
378static struct mt312_config skystar23_samsung_tbdu18132_config = {
379
380 .demod_address = 0x0e,
381 .pll_set = skystar23_samsung_tbdu18132_pll_set,
382};
383
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700384
385static u8 alps_tdee4_stv0297_inittab[] = {
386 0x80, 0x01,
387 0x80, 0x00,
388 0x81, 0x01,
389 0x81, 0x00,
390 0x00, 0x09,
391 0x01, 0x69,
392 0x03, 0x00,
393 0x04, 0x00,
394 0x07, 0x00,
395 0x08, 0x00,
396 0x20, 0x00,
397 0x21, 0x40,
398 0x22, 0x00,
399 0x23, 0x00,
400 0x24, 0x40,
401 0x25, 0x88,
402 0x30, 0xff,
403 0x31, 0x00,
404 0x32, 0xff,
405 0x33, 0x00,
406 0x34, 0x50,
407 0x35, 0x7f,
408 0x36, 0x00,
409 0x37, 0x20,
410 0x38, 0x00,
411 0x40, 0x1c,
412 0x41, 0xff,
413 0x42, 0x29,
414 0x43, 0x00,
415 0x44, 0xff,
416 0x45, 0x00,
417 0x46, 0x00,
418 0x49, 0x04,
419 0x4a, 0x00,
420 0x4b, 0xf8,
421 0x52, 0x30,
422 0x55, 0xae,
423 0x56, 0x47,
424 0x57, 0xe1,
425 0x58, 0x3a,
426 0x5a, 0x1e,
427 0x5b, 0x34,
428 0x60, 0x00,
429 0x63, 0x00,
430 0x64, 0x00,
431 0x65, 0x00,
432 0x66, 0x00,
433 0x67, 0x00,
434 0x68, 0x00,
435 0x69, 0x00,
436 0x6a, 0x02,
437 0x6b, 0x00,
438 0x70, 0xff,
439 0x71, 0x00,
440 0x72, 0x00,
441 0x73, 0x00,
442 0x74, 0x0c,
443 0x80, 0x00,
444 0x81, 0x00,
445 0x82, 0x00,
446 0x83, 0x00,
447 0x84, 0x04,
448 0x85, 0x80,
449 0x86, 0x24,
450 0x87, 0x78,
451 0x88, 0x10,
452 0x89, 0x00,
453 0x90, 0x01,
454 0x91, 0x01,
455 0xa0, 0x04,
456 0xa1, 0x00,
457 0xa2, 0x00,
458 0xb0, 0x91,
459 0xb1, 0x0b,
460 0xc0, 0x53,
461 0xc1, 0x70,
462 0xc2, 0x12,
463 0xd0, 0x00,
464 0xd1, 0x00,
465 0xd2, 0x00,
466 0xd3, 0x00,
467 0xd4, 0x00,
468 0xd5, 0x00,
469 0xde, 0x00,
470 0xdf, 0x00,
471 0x61, 0x49,
472 0x62, 0x0b,
473 0x53, 0x08,
474 0x59, 0x08,
475 0xff, 0xff,
476};
477
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700478static struct stv0297_config alps_tdee4_stv0297_config = {
479 .demod_address = 0x1c,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700480 .inittab = alps_tdee4_stv0297_inittab,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700481// .invert = 1,
482// .pll_set = alps_tdee4_stv0297_pll_set,
483};
484
485/* try to figure out the frontend, each card/box can have on of the following list */
486int flexcop_frontend_init(struct flexcop_device *fc)
487{
488 /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
489 if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
490 fc->fe->ops->set_voltage = flexcop_set_voltage;
491
492 fc->fe_sleep = fc->fe->ops->sleep;
493 fc->fe->ops->sleep = flexcop_sleep;
494
495 fc->dev_type = FC_SKY;
496 info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
497 } else
498 /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
499 if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
500 fc->dev_type = FC_AIR_DVB;
501 info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
502 } else
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700503 /* try the air atsc 2nd generation (nxt2002) */
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700504 if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700505 fc->dev_type = FC_AIR_ATSC2;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700506 info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
507 } else
Michael Krufkyc0b11b92005-11-08 21:35:32 -0800508 /* try the air atsc 3nd generation (lgdt3303) */
509 if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
510 fc->dev_type = FC_AIR_ATSC3;
511 info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
512 } else
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700513 /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
514 if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
515 fc->dev_type = FC_AIR_ATSC1;
516 info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
517 } else
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700518 /* try the cable dvb (stv0297) */
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700519 if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700520 fc->dev_type = FC_CABLE;
521 info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
522 } else
523 /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
524 if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
525 fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
526 fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
527 fc->fe->ops->set_tone = flexcop_set_tone;
528 fc->fe->ops->set_voltage = flexcop_set_voltage;
529
530 fc->fe_sleep = fc->fe->ops->sleep;
531 fc->fe->ops->sleep = flexcop_sleep;
532
533 fc->dev_type = FC_SKY_OLD;
534 info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
535 }
536
537 if (fc->fe == NULL) {
538 err("no frontend driver found for this B2C2/FlexCop adapter");
539 return -ENODEV;
540 } else {
541 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
542 err("frontend registration failed!");
543 if (fc->fe->ops->release != NULL)
544 fc->fe->ops->release(fc->fe);
545 fc->fe = NULL;
546 return -EINVAL;
547 }
548 }
549 fc->init_state |= FC_STATE_FE_INIT;
550 return 0;
551}
552
553void flexcop_frontend_exit(struct flexcop_device *fc)
554{
555 if (fc->init_state & FC_STATE_FE_INIT)
556 dvb_unregister_frontend(fc->fe);
557
558 fc->init_state &= ~FC_STATE_FE_INIT;
559}