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 "nxt200x.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_tuner_set_params(struct dvb_frontend* fe, 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	struct flexcop_device *fc = fe->dvb->priv;
175
176	div = params->frequency / 125;
177
178	buf[0] = (div >> 8) & 0x7f;
179	buf[1] = div & 0xff;
180	buf[2] = 0x84;  /* 0xC4 */
181	buf[3] = 0x08;
182
183	if (params->frequency < 1500000) buf[3] |= 0x10;
184
185	if (fe->ops.i2c_gate_ctrl)
186		fe->ops.i2c_gate_ctrl(fe, 1);
187	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
188		return -EIO;
189	}
190	return 0;
191}
192
193static u8 samsung_tbmu24112_inittab[] = {
194	     0x01, 0x15,
195	     0x02, 0x30,
196	     0x03, 0x00,
197	     0x04, 0x7D,
198	     0x05, 0x35,
199	     0x06, 0x02,
200	     0x07, 0x00,
201	     0x08, 0xC3,
202	     0x0C, 0x00,
203	     0x0D, 0x81,
204	     0x0E, 0x23,
205	     0x0F, 0x12,
206	     0x10, 0x7E,
207	     0x11, 0x84,
208	     0x12, 0xB9,
209	     0x13, 0x88,
210	     0x14, 0x89,
211	     0x15, 0xC9,
212	     0x16, 0x00,
213	     0x17, 0x5C,
214	     0x18, 0x00,
215	     0x19, 0x00,
216	     0x1A, 0x00,
217	     0x1C, 0x00,
218	     0x1D, 0x00,
219	     0x1E, 0x00,
220	     0x1F, 0x3A,
221	     0x20, 0x2E,
222	     0x21, 0x80,
223	     0x22, 0xFF,
224	     0x23, 0xC1,
225	     0x28, 0x00,
226	     0x29, 0x1E,
227	     0x2A, 0x14,
228	     0x2B, 0x0F,
229	     0x2C, 0x09,
230	     0x2D, 0x05,
231	     0x31, 0x1F,
232	     0x32, 0x19,
233	     0x33, 0xFE,
234	     0x34, 0x93,
235	     0xff, 0xff,
236};
237
238static struct stv0299_config samsung_tbmu24112_config = {
239	.demod_address = 0x68,
240	.inittab = samsung_tbmu24112_inittab,
241	.mclk = 88000000UL,
242	.invert = 0,
243	.skip_reinit = 0,
244	.lock_output = STV0229_LOCKOUTPUT_LK,
245	.volt13_op0_op1 = STV0299_VOLT13_OP1,
246	.min_delay_ms = 100,
247	.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
248};
249
250/* dvb-t mt352 */
251static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
252{
253	static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
254	static u8 mt352_reset [] = { 0x50, 0x80 };
255	static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
256	static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
257	static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
258
259	mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
260	udelay(2000);
261	mt352_write(fe, mt352_reset, sizeof(mt352_reset));
262	mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
263
264	mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
265	mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
266
267	return 0;
268}
269
270static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
271{
272	u32 div;
273	unsigned char bs = 0;
274
275	if (buf_len < 5)
276		return -EINVAL;
277
278	#define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
279	div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
280
281	if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
282	if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
283	if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
284
285	pllbuf[0] = 0x61;
286	pllbuf[1] = div >> 8;
287	pllbuf[2] = div & 0xff;
288	pllbuf[3] = 0xcc;
289	pllbuf[4] = bs;
290
291	return 5;
292}
293
294static struct mt352_config samsung_tdtc9251dh0_config = {
295	.demod_address = 0x0f,
296	.demod_init    = samsung_tdtc9251dh0_demod_init,
297};
298
299static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
300{
301	struct flexcop_device *fc = fe->dvb->priv;
302	return request_firmware(fw, name, fc->dev);
303}
304
305static struct lgdt330x_config air2pc_atsc_hd5000_config = {
306	.demod_address       = 0x59,
307	.demod_chip          = LGDT3303,
308	.serial_mpeg         = 0x04,
309	.clock_polarity_flip = 1,
310};
311
312static struct nxt200x_config samsung_tbmv_config = {
313	.demod_address    = 0x0a,
314};
315
316static struct bcm3510_config air2pc_atsc_first_gen_config = {
317	.demod_address    = 0x0f,
318	.request_firmware = flexcop_fe_request_firmware,
319};
320
321static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
322{
323	u8 buf[4];
324	u32 div;
325	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
326	struct flexcop_device *fc = fe->dvb->priv;
327
328	div = (params->frequency + (125/2)) / 125;
329
330	buf[0] = (div >> 8) & 0x7f;
331	buf[1] = (div >> 0) & 0xff;
332	buf[2] = 0x84 | ((div >> 10) & 0x60);
333	buf[3] = 0x80;
334
335	if (params->frequency < 1550000)
336		buf[3] |= 0x02;
337
338	if (fe->ops.i2c_gate_ctrl)
339		fe->ops.i2c_gate_ctrl(fe, 1);
340	if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
341		return -EIO;
342	return 0;
343}
344
345static struct mt312_config skystar23_samsung_tbdu18132_config = {
346
347	.demod_address = 0x0e,
348};
349
350static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
351					       struct dvb_frontend_parameters *fep)
352{
353	struct flexcop_device *fc = fe->dvb->priv;
354	u8 buf[4];
355	u16 div;
356	int ret;
357
358/*  62.5 kHz * 10 */
359#define REF_FREQ    625
360#define FREQ_OFFSET 36125
361
362	div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
363
364	buf[0] = (u8)( div >> 8) & 0x7f;
365	buf[1] = (u8)        div & 0xff;
366
367/* F(osc) = N * Reference Freq. (62.5 kHz)
368 * byte 2 :  0 N14 N13 N12 N11 N10 N9  N8
369 * byte 3 : N7 N6  N5  N4  N3  N2  N1  N0
370 * byte 4 : 1  *   *   AGD R3  R2  R1  R0
371 * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
372 * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
373	buf[2] = 0x95;
374
375// Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
376//  47 - 153   0  *  0   0   0   0   0   1   0x01
377// 153 - 430   0  *  0   0   0   0   1   0   0x02
378// 430 - 822   0  *  0   0   1   0   0   0   0x08
379// 822 - 862   1  *  0   0   1   0   0   0   0x88
380
381	     if (fep->frequency <= 153000000) buf[3] = 0x01;
382	else if (fep->frequency <= 430000000) buf[3] = 0x02;
383	else if (fep->frequency <= 822000000) buf[3] = 0x08;
384	else buf[3] = 0x88;
385
386	if (fe->ops.i2c_gate_ctrl)
387		fe->ops.i2c_gate_ctrl(fe, 0);
388	deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
389	ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
390	deb_tuner("tuner write returned: %d\n",ret);
391
392	return 0;
393}
394
395static u8 alps_tdee4_stv0297_inittab[] = {
396	0x80, 0x01,
397	0x80, 0x00,
398	0x81, 0x01,
399	0x81, 0x00,
400	0x00, 0x48,
401	0x01, 0x58,
402	0x03, 0x00,
403	0x04, 0x00,
404	0x07, 0x00,
405	0x08, 0x00,
406	0x30, 0xff,
407	0x31, 0x9d,
408	0x32, 0xff,
409	0x33, 0x00,
410	0x34, 0x29,
411	0x35, 0x55,
412	0x36, 0x80,
413	0x37, 0x6e,
414	0x38, 0x9c,
415	0x40, 0x1a,
416	0x41, 0xfe,
417	0x42, 0x33,
418	0x43, 0x00,
419	0x44, 0xff,
420	0x45, 0x00,
421	0x46, 0x00,
422	0x49, 0x04,
423	0x4a, 0x51,
424	0x4b, 0xf8,
425	0x52, 0x30,
426	0x53, 0x06,
427	0x59, 0x06,
428	0x5a, 0x5e,
429	0x5b, 0x04,
430	0x61, 0x49,
431	0x62, 0x0a,
432	0x70, 0xff,
433	0x71, 0x04,
434	0x72, 0x00,
435	0x73, 0x00,
436	0x74, 0x0c,
437	0x80, 0x20,
438	0x81, 0x00,
439	0x82, 0x30,
440	0x83, 0x00,
441	0x84, 0x04,
442	0x85, 0x22,
443	0x86, 0x08,
444	0x87, 0x1b,
445	0x88, 0x00,
446	0x89, 0x00,
447	0x90, 0x00,
448	0x91, 0x04,
449	0xa0, 0x86,
450	0xa1, 0x00,
451	0xa2, 0x00,
452	0xb0, 0x91,
453	0xb1, 0x0b,
454	0xc0, 0x5b,
455	0xc1, 0x10,
456	0xc2, 0x12,
457	0xd0, 0x02,
458	0xd1, 0x00,
459	0xd2, 0x00,
460	0xd3, 0x00,
461	0xd4, 0x02,
462	0xd5, 0x00,
463	0xde, 0x00,
464	0xdf, 0x01,
465	0xff, 0xff,
466};
467
468static struct stv0297_config alps_tdee4_stv0297_config = {
469	.demod_address = 0x1c,
470	.inittab = alps_tdee4_stv0297_inittab,
471//	.invert = 1,
472//	.pll_set = alps_tdee4_stv0297_pll_set,
473};
474
475/* try to figure out the frontend, each card/box can have on of the following list */
476int flexcop_frontend_init(struct flexcop_device *fc)
477{
478	struct dvb_frontend_ops *ops;
479
480	/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
481	if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
482		ops = &fc->fe->ops;
483
484		ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
485
486		ops->set_voltage = flexcop_set_voltage;
487
488		fc->fe_sleep             = ops->sleep;
489		ops->sleep               = flexcop_sleep;
490
491		fc->dev_type          = FC_SKY;
492		info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
493	} else
494	/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
495	if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
496		fc->dev_type          = FC_AIR_DVB;
497		fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
498		info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
499	} else
500	/* try the air atsc 2nd generation (nxt2002) */
501	if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
502		fc->dev_type          = FC_AIR_ATSC2;
503		dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, &dvb_pll_samsung_tbmv);
504		info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
505	} else
506	/* try the air atsc 3nd generation (lgdt3303) */
507	if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
508		fc->dev_type          = FC_AIR_ATSC3;
509		dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_lg_tdvs_h06xf);
510		info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
511	} else
512	/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
513	if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
514		fc->dev_type          = FC_AIR_ATSC1;
515		info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
516	} else
517	/* try the cable dvb (stv0297) */
518	if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
519		fc->dev_type                        = FC_CABLE;
520		fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
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 = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
525		ops = &fc->fe->ops;
526
527		ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
528
529		ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
530		ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
531		ops->set_tone               = flexcop_set_tone;
532		ops->set_voltage            = flexcop_set_voltage;
533
534		fc->fe_sleep                = ops->sleep;
535		ops->sleep                  = flexcop_sleep;
536
537		fc->dev_type                = FC_SKY_OLD;
538		info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
539	}
540
541	if (fc->fe == NULL) {
542		err("no frontend driver found for this B2C2/FlexCop adapter");
543		return -ENODEV;
544	} else {
545		if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
546			err("frontend registration failed!");
547			dvb_frontend_detach(fc->fe);
548			fc->fe = NULL;
549			return -EINVAL;
550		}
551	}
552	fc->init_state |= FC_STATE_FE_INIT;
553	return 0;
554}
555
556void flexcop_frontend_exit(struct flexcop_device *fc)
557{
558	if (fc->init_state & FC_STATE_FE_INIT) {
559		dvb_unregister_frontend(fc->fe);
560		dvb_frontend_detach(fc->fe);
561	}
562
563	fc->init_state &= ~FC_STATE_FE_INIT;
564}
565