blob: 0410cc96a48e2cc3a90238ab92e4dd45904d4e2f [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
167static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
168{
169 u8 buf[4];
170 u32 div;
171 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
172 struct flexcop_device *fc = fe->dvb->priv;
173
174 div = params->frequency / 125;
175
176 buf[0] = (div >> 8) & 0x7f;
177 buf[1] = div & 0xff;
178 buf[2] = 0x84; /* 0xC4 */
179 buf[3] = 0x08;
180
181 if (params->frequency < 1500000) buf[3] |= 0x10;
182
183 if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
184 return -EIO;
185 return 0;
186}
187
188static u8 samsung_tbmu24112_inittab[] = {
189 0x01, 0x15,
190 0x02, 0x30,
191 0x03, 0x00,
192 0x04, 0x7D,
193 0x05, 0x35,
194 0x06, 0x02,
195 0x07, 0x00,
196 0x08, 0xC3,
197 0x0C, 0x00,
198 0x0D, 0x81,
199 0x0E, 0x23,
200 0x0F, 0x12,
201 0x10, 0x7E,
202 0x11, 0x84,
203 0x12, 0xB9,
204 0x13, 0x88,
205 0x14, 0x89,
206 0x15, 0xC9,
207 0x16, 0x00,
208 0x17, 0x5C,
209 0x18, 0x00,
210 0x19, 0x00,
211 0x1A, 0x00,
212 0x1C, 0x00,
213 0x1D, 0x00,
214 0x1E, 0x00,
215 0x1F, 0x3A,
216 0x20, 0x2E,
217 0x21, 0x80,
218 0x22, 0xFF,
219 0x23, 0xC1,
220 0x28, 0x00,
221 0x29, 0x1E,
222 0x2A, 0x14,
223 0x2B, 0x0F,
224 0x2C, 0x09,
225 0x2D, 0x05,
226 0x31, 0x1F,
227 0x32, 0x19,
228 0x33, 0xFE,
229 0x34, 0x93,
230 0xff, 0xff,
231};
232
233static struct stv0299_config samsung_tbmu24112_config = {
234 .demod_address = 0x68,
235 .inittab = samsung_tbmu24112_inittab,
236 .mclk = 88000000UL,
237 .invert = 0,
238 .enhanced_tuning = 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 = {
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
300static struct nxt2002_config samsung_tbmv_config = {
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700301 .demod_address = 0x0a,
302 .request_firmware = flexcop_fe_request_firmware,
303};
304
305static struct bcm3510_config air2pc_atsc_first_gen_config = {
306 .demod_address = 0x0f,
307 .request_firmware = flexcop_fe_request_firmware,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700308};
309
310static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
311{
312 u8 buf[4];
313 u32 div;
314 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
315 struct flexcop_device *fc = fe->dvb->priv;
316
317 div = (params->frequency + (125/2)) / 125;
318
319 buf[0] = (div >> 8) & 0x7f;
320 buf[1] = (div >> 0) & 0xff;
321 buf[2] = 0x84 | ((div >> 10) & 0x60);
322 buf[3] = 0x80;
323
324 if (params->frequency < 1550000)
325 buf[3] |= 0x02;
326
327 if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
328 return -EIO;
329 return 0;
330}
331
332static struct mt312_config skystar23_samsung_tbdu18132_config = {
333
334 .demod_address = 0x0e,
335 .pll_set = skystar23_samsung_tbdu18132_pll_set,
336};
337
338static struct stv0297_config alps_tdee4_stv0297_config = {
339 .demod_address = 0x1c,
340// .invert = 1,
341// .pll_set = alps_tdee4_stv0297_pll_set,
342};
343
344/* try to figure out the frontend, each card/box can have on of the following list */
345int flexcop_frontend_init(struct flexcop_device *fc)
346{
347 /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
348 if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
349 fc->fe->ops->set_voltage = flexcop_set_voltage;
350
351 fc->fe_sleep = fc->fe->ops->sleep;
352 fc->fe->ops->sleep = flexcop_sleep;
353
354 fc->dev_type = FC_SKY;
355 info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
356 } else
357 /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
358 if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
359 fc->dev_type = FC_AIR_DVB;
360 info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
361 } else
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700362 /* try the air atsc 2nd generation (nxt2002) */
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700363 if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700364 fc->dev_type = FC_AIR_ATSC2;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700365 info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
366 } else
Johannes Stezenbach55f51ef2005-06-23 22:02:41 -0700367 /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
368 if ((fc->fe = bcm3510_attach(&air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
369 fc->dev_type = FC_AIR_ATSC1;
370 info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
371 } else
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700372 /* try the cable dvb (stv0297) */
373 if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
374 fc->dev_type = FC_CABLE;
375 info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
376 } else
377 /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
378 if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
379 fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
380 fc->fe->ops->diseqc_send_burst = flexcop_diseqc_send_burst;
381 fc->fe->ops->set_tone = flexcop_set_tone;
382 fc->fe->ops->set_voltage = flexcop_set_voltage;
383
384 fc->fe_sleep = fc->fe->ops->sleep;
385 fc->fe->ops->sleep = flexcop_sleep;
386
387 fc->dev_type = FC_SKY_OLD;
388 info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
389 }
390
391 if (fc->fe == NULL) {
392 err("no frontend driver found for this B2C2/FlexCop adapter");
393 return -ENODEV;
394 } else {
395 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
396 err("frontend registration failed!");
397 if (fc->fe->ops->release != NULL)
398 fc->fe->ops->release(fc->fe);
399 fc->fe = NULL;
400 return -EINVAL;
401 }
402 }
403 fc->init_state |= FC_STATE_FE_INIT;
404 return 0;
405}
406
407void flexcop_frontend_exit(struct flexcop_device *fc)
408{
409 if (fc->init_state & FC_STATE_FE_INIT)
410 dvb_unregister_frontend(fc->fe);
411
412 fc->init_state &= ~FC_STATE_FE_INIT;
413}