flexcop-fe-tuner.c revision 50c25fff5385c6baf3114f7c369b0f75a29ac1e8
1/*
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"
13#include "bcm3510.h"
14#include "stv0297.h"
15#include "mt312.h"
16#include "lgdt330x.h"
17#include "dvb-pll.h"
18
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
85	v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
86	v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
87
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
169static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params)
170{
171	u8 buf[4];
172	u32 div;
173	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
174
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
184	if (i2c_transfer(i2c, &msg, 1) != 1)
185		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,
239	.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 = {
289	.demod_address = 0x0f,
290	.demod_init    = samsung_tdtc9251dh0_demod_init,
291	.pll_set       = samsung_tdtc9251dh0_pll_set,
292};
293
294static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
295{
296	struct flexcop_device *fc = fe->dvb->priv;
297	return request_firmware(fw, name, fc->dev);
298}
299
300static 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
346static struct nxt2002_config samsung_tbmv_config = {
347	.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,
354};
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
384
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
478static struct stv0297_config alps_tdee4_stv0297_config = {
479	.demod_address = 0x1c,
480	.inittab = alps_tdee4_stv0297_inittab,
481//	.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	struct dvb_frontend_ops *ops;
489
490	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
491	if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
492		ops = fc->fe->ops;
493
494		ops->set_voltage = flexcop_set_voltage;
495
496		fc->fe_sleep             = ops->sleep;
497		ops->sleep               = flexcop_sleep;
498
499		fc->dev_type          = FC_SKY;
500		info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
501	} else
502	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
503	if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
504		fc->dev_type          = FC_AIR_DVB;
505		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
506	} else
507	/* try the air atsc 2nd generation (nxt2002) */
508	if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
509		fc->dev_type          = FC_AIR_ATSC2;
510		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
511	} else
512	/* try the air atsc 3nd generation (lgdt3303) */
513	if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
514		fc->dev_type          = FC_AIR_ATSC3;
515		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
516	} else
517	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
518	if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
519		fc->dev_type          = FC_AIR_ATSC1;
520		info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
521	} else
522	/* try the cable dvb (stv0297) */
523	if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
524		fc->dev_type                        = FC_CABLE;
525		info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
526	} else
527	/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
528	if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
529		ops = fc->fe->ops;
530
531		ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
532		ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
533		ops->set_tone               = flexcop_set_tone;
534		ops->set_voltage            = flexcop_set_voltage;
535
536		fc->fe_sleep                = ops->sleep;
537		ops->sleep                  = flexcop_sleep;
538
539		fc->dev_type                = FC_SKY_OLD;
540		info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
541	}
542
543	if (fc->fe == NULL) {
544		err("no frontend driver found for this B2C2/FlexCop adapter");
545		return -ENODEV;
546	} else {
547		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
548			err("frontend registration failed!");
549			ops = fc->fe->ops;
550			if (ops->release != NULL)
551				ops->release(fc->fe);
552			fc->fe = NULL;
553			return -EINVAL;
554		}
555	}
556	fc->init_state |= FC_STATE_FE_INIT;
557	return 0;
558}
559
560void flexcop_frontend_exit(struct flexcop_device *fc)
561{
562	if (fc->init_state & FC_STATE_FE_INIT)
563		dvb_unregister_frontend(fc->fe);
564
565	fc->init_state &= ~FC_STATE_FE_INIT;
566}
567