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