blob: efb4a6c2b57a5d39cf9c70a5cef455a9dbb528e4 [file] [log] [blame]
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07001/*
Patrick Boettcherd66b94b2009-05-20 05:08:26 -03002 * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
3 * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
4 * see flexcop.c for copyright information
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07005 */
Michael Krufky827855d2008-04-22 14:46:16 -03006#include <media/tuner.h>
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07007#include "flexcop.h"
Johannes Stezenbach2add87a2005-05-16 21:54:10 -07008#include "mt312.h"
Patrick Boettcherd66b94b2009-05-20 05:08:26 -03009#include "stv0299.h"
Patrick Boettcherca19aaa2008-04-13 15:49:22 -030010#include "s5h1420.h"
11#include "itd1000.h"
Patrick Boettcherc9dd82c2008-03-29 21:28:07 -030012#include "cx24113.h"
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030013#include "cx24123.h"
Patrick Boettcherc9dd82c2008-03-29 21:28:07 -030014#include "isl6421.h"
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030015#include "mt352.h"
16#include "bcm3510.h"
17#include "nxt200x.h"
18#include "dvb-pll.h"
19#include "lgdt330x.h"
20#include "tuner-simple.h"
21#include "stv0297.h"
Patrick Boettcherc9dd82c2008-03-29 21:28:07 -030022
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070023/* lnb control */
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030024#if defined(CONFIG_DVB_MT312_MODULE) || defined(CONFIG_DVB_STV0299_MODULE)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070025static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
26{
27 struct flexcop_device *fc = fe->dvb->priv;
28 flexcop_ibi_value v;
29 deb_tuner("polarity/voltage = %u\n", voltage);
30
31 v = fc->read_ibi_reg(fc, misc_204);
32 switch (voltage) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030033 case SEC_VOLTAGE_OFF:
34 v.misc_204.ACPI1_sig = 1;
35 break;
36 case SEC_VOLTAGE_13:
37 v.misc_204.ACPI1_sig = 0;
38 v.misc_204.LNB_L_H_sig = 0;
39 break;
40 case SEC_VOLTAGE_18:
41 v.misc_204.ACPI1_sig = 0;
42 v.misc_204.LNB_L_H_sig = 1;
43 break;
44 default:
45 err("unknown SEC_VOLTAGE value");
46 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070047 }
48 return fc->write_ibi_reg(fc, misc_204, v);
49}
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030050#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070051
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030052#if defined(CONFIG_DVB_S5H1420_MODULE) || defined(CONFIG_DVB_STV0299_MODULE) \
53 || defined(CONFIG_DVB_MT312_MODULE)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070054static int flexcop_sleep(struct dvb_frontend* fe)
55{
56 struct flexcop_device *fc = fe->dvb->priv;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070057 if (fc->fe_sleep)
58 return fc->fe_sleep(fe);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070059 return 0;
60}
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030061#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070062
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030063/* SkyStar2 DVB-S rev 2.3 */
64#if defined(CONFIG_DVB_MT312_MODULE)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070065static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
66{
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030067/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070068 struct flexcop_device *fc = fe->dvb->priv;
69 flexcop_ibi_value v;
70 u16 ax;
71 v.raw = 0;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070072 deb_tuner("tone = %u\n",tone);
73
74 switch (tone) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030075 case SEC_TONE_ON:
76 ax = 0x01ff;
77 break;
78 case SEC_TONE_OFF:
79 ax = 0;
80 break;
81 default:
82 err("unknown SEC_TONE value");
83 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070084 }
85
86 v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
Johannes Stezenbach958706c2005-05-16 21:54:19 -070087 v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
88 v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070089 return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
90}
91
92static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
93{
94 flexcop_set_tone(fe, SEC_TONE_ON);
95 udelay(data ? 500 : 1000);
96 flexcop_set_tone(fe, SEC_TONE_OFF);
97 udelay(data ? 1000 : 500);
98}
99
100static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
101{
102 int i, par = 1, d;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700103 for (i = 7; i >= 0; i--) {
104 d = (data >> i) & 1;
105 par ^= d;
106 flexcop_diseqc_send_bit(fe, d);
107 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700108 flexcop_diseqc_send_bit(fe, par);
109}
110
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300111static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
112 int len, u8 *msg, unsigned long burst)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700113{
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]);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700121 mdelay(16);
122
123 if (burst != -1) {
124 if (burst)
125 flexcop_diseqc_send_byte(fe, 0xff);
126 else {
127 flexcop_set_tone(fe, SEC_TONE_ON);
Thierry MERLEc4e3fd92008-09-01 17:32:10 -0300128 mdelay(12);
129 udelay(500);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700130 flexcop_set_tone(fe, SEC_TONE_OFF);
131 }
132 msleep(20);
133 }
134 return 0;
135}
136
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300137static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
138 struct dvb_diseqc_master_cmd *cmd)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700139{
140 return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
141}
142
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300143static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
144 fe_sec_mini_cmd_t minicmd)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700145{
146 return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
147}
148
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300149static struct mt312_config skystar23_samsung_tbdu18132_config = {
150 .demod_address = 0x0e,
151};
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700152
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300153static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
154 struct dvb_frontend_parameters *params)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700155{
156 u8 buf[4];
157 u32 div;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300158 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
159 .len = sizeof(buf) };
Andrew de Quincey56e03142006-04-18 17:47:12 -0300160 struct flexcop_device *fc = fe->dvb->priv;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700161 div = (params->frequency + (125/2)) / 125;
162
163 buf[0] = (div >> 8) & 0x7f;
164 buf[1] = (div >> 0) & 0xff;
165 buf[2] = 0x84 | ((div >> 10) & 0x60);
166 buf[3] = 0x80;
167
168 if (params->frequency < 1550000)
169 buf[3] |= 0x02;
170
Patrick Boettcherdea74862006-05-14 05:01:31 -0300171 if (fe->ops.i2c_gate_ctrl)
172 fe->ops.i2c_gate_ctrl(fe, 1);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300173 if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700174 return -EIO;
175 return 0;
176}
177
Trent Piephoeccd15a2009-06-11 05:33:00 -0300178static int skystar2_rev23_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300179 struct i2c_adapter *i2c)
180{
Trent Piephoeccd15a2009-06-11 05:33:00 -0300181 fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300182 if (fc->fe != NULL) {
183 struct dvb_frontend_ops *ops = &fc->fe->ops;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300184 ops->tuner_ops.set_params =
185 skystar23_samsung_tbdu18132_tuner_set_params;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300186 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
187 ops->diseqc_send_burst = flexcop_diseqc_send_burst;
188 ops->set_tone = flexcop_set_tone;
189 ops->set_voltage = flexcop_set_voltage;
190 fc->fe_sleep = ops->sleep;
191 ops->sleep = flexcop_sleep;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300192 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300193 }
Trent Piephoeccd15a2009-06-11 05:33:00 -0300194 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300195}
196#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700197
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300198/* SkyStar2 DVB-S rev 2.6 */
199#if defined(CONFIG_DVB_STV0299_MODULE)
200static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
201 u32 srate, u32 ratio)
202{
203 u8 aclk = 0;
204 u8 bclk = 0;
205
206 if (srate < 1500000) {
207 aclk = 0xb7; bclk = 0x47;
208 } else if (srate < 3000000) {
209 aclk = 0xb7; bclk = 0x4b;
210 } else if (srate < 7000000) {
211 aclk = 0xb7; bclk = 0x4f;
212 } else if (srate < 14000000) {
213 aclk = 0xb7; bclk = 0x53;
214 } else if (srate < 30000000) {
215 aclk = 0xb6; bclk = 0x53;
216 } else if (srate < 45000000) {
217 aclk = 0xb4; bclk = 0x51;
218 }
219
220 stv0299_writereg(fe, 0x13, aclk);
221 stv0299_writereg(fe, 0x14, bclk);
222 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
223 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
224 stv0299_writereg(fe, 0x21, ratio & 0xf0);
225 return 0;
226}
227
228static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
229 struct dvb_frontend_parameters *params)
230{
231 u8 buf[4];
232 u32 div;
233 struct i2c_msg msg = {
234 .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
235 struct flexcop_device *fc = fe->dvb->priv;
236 div = params->frequency / 125;
237
238 buf[0] = (div >> 8) & 0x7f;
239 buf[1] = div & 0xff;
240 buf[2] = 0x84; /* 0xC4 */
241 buf[3] = 0x08;
242
243 if (params->frequency < 1500000)
244 buf[3] |= 0x10;
245
246 if (fe->ops.i2c_gate_ctrl)
247 fe->ops.i2c_gate_ctrl(fe, 1);
248 if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
249 return -EIO;
250 return 0;
251}
252
253static u8 samsung_tbmu24112_inittab[] = {
254 0x01, 0x15,
255 0x02, 0x30,
256 0x03, 0x00,
257 0x04, 0x7D,
258 0x05, 0x35,
259 0x06, 0x02,
260 0x07, 0x00,
261 0x08, 0xC3,
262 0x0C, 0x00,
263 0x0D, 0x81,
264 0x0E, 0x23,
265 0x0F, 0x12,
266 0x10, 0x7E,
267 0x11, 0x84,
268 0x12, 0xB9,
269 0x13, 0x88,
270 0x14, 0x89,
271 0x15, 0xC9,
272 0x16, 0x00,
273 0x17, 0x5C,
274 0x18, 0x00,
275 0x19, 0x00,
276 0x1A, 0x00,
277 0x1C, 0x00,
278 0x1D, 0x00,
279 0x1E, 0x00,
280 0x1F, 0x3A,
281 0x20, 0x2E,
282 0x21, 0x80,
283 0x22, 0xFF,
284 0x23, 0xC1,
285 0x28, 0x00,
286 0x29, 0x1E,
287 0x2A, 0x14,
288 0x2B, 0x0F,
289 0x2C, 0x09,
290 0x2D, 0x05,
291 0x31, 0x1F,
292 0x32, 0x19,
293 0x33, 0xFE,
294 0x34, 0x93,
295 0xff, 0xff,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700296};
297
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300298static struct stv0299_config samsung_tbmu24112_config = {
299 .demod_address = 0x68,
300 .inittab = samsung_tbmu24112_inittab,
301 .mclk = 88000000UL,
302 .invert = 0,
303 .skip_reinit = 0,
304 .lock_output = STV0299_LOCKOUTPUT_LK,
305 .volt13_op0_op1 = STV0299_VOLT13_OP1,
306 .min_delay_ms = 100,
307 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
308};
309
Trent Piephoeccd15a2009-06-11 05:33:00 -0300310static int skystar2_rev26_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300311 struct i2c_adapter *i2c)
312{
313 fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
314 if (fc->fe != NULL) {
315 struct dvb_frontend_ops *ops = &fc->fe->ops;
316 ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
317 ops->set_voltage = flexcop_set_voltage;
318 fc->fe_sleep = ops->sleep;
319 ops->sleep = flexcop_sleep;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300320 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300321 }
Trent Piephoeccd15a2009-06-11 05:33:00 -0300322 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300323}
324#endif
325
326/* SkyStar2 DVB-S rev 2.7 */
327#if defined(CONFIG_DVB_S5H1420_MODULE)
328static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
329 .demod_address = 0x53,
330 .invert = 1,
331 .repeated_start_workaround = 1,
332 .serial_mpeg = 1,
333};
334
335static struct itd1000_config skystar2_rev2_7_itd1000_config = {
336 .i2c_address = 0x61,
337};
338
Trent Piephoeccd15a2009-06-11 05:33:00 -0300339static int skystar2_rev27_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300340 struct i2c_adapter *i2c)
341{
Trent Piephoeccd15a2009-06-11 05:33:00 -0300342 flexcop_ibi_value r108;
343 struct i2c_adapter *i2c_tuner;
344
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300345 /* enable no_base_addr - no repeated start when reading */
346 fc->fc_i2c_adap[0].no_base_addr = 1;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300347 fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
348 i2c);
349 if (!fc->fe)
350 goto fail;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300351
Trent Piephoeccd15a2009-06-11 05:33:00 -0300352 i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
353 if (!i2c_tuner)
354 goto fail;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300355
Trent Piephoeccd15a2009-06-11 05:33:00 -0300356 fc->fe_sleep = fc->fe->ops.sleep;
357 fc->fe->ops.sleep = flexcop_sleep;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300358
Trent Piephoeccd15a2009-06-11 05:33:00 -0300359 /* enable no_base_addr - no repeated start when reading */
360 fc->fc_i2c_adap[2].no_base_addr = 1;
361 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
362 0x08, 1, 1)) {
363 err("ISL6421 could NOT be attached");
364 goto fail_isl;
365 }
366 info("ISL6421 successfully attached");
367
368 /* the ITD1000 requires a lower i2c clock - is it a problem ? */
369 r108.raw = 0x00000506;
370 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
371 if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
372 &skystar2_rev2_7_itd1000_config)) {
373 err("ITD1000 could NOT be attached");
374 /* Should i2c clock be restored? */
375 goto fail_isl;
376 }
377 info("ITD1000 successfully attached");
378
379 return 1;
380
381fail_isl:
382 fc->fc_i2c_adap[2].no_base_addr = 0;
383fail:
384 /* for the next devices we need it again */
385 fc->fc_i2c_adap[0].no_base_addr = 0;
386 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300387}
388#endif
389
390/* SkyStar2 rev 2.8 */
391#if defined(CONFIG_DVB_CX24123_MODULE)
392static struct cx24123_config skystar2_rev2_8_cx24123_config = {
393 .demod_address = 0x55,
394 .dont_use_pll = 1,
395 .agc_callback = cx24113_agc_callback,
396};
397
398static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
399 .i2c_addr = 0x54,
400 .xtal_khz = 10111,
401};
402
Trent Piephoeccd15a2009-06-11 05:33:00 -0300403static int skystar2_rev28_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300404 struct i2c_adapter *i2c)
405{
Trent Piephoeccd15a2009-06-11 05:33:00 -0300406 struct i2c_adapter *i2c_tuner;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300407
Trent Piephoeccd15a2009-06-11 05:33:00 -0300408 fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
409 i2c);
410 if (!fc->fe)
411 return 0;
412
413 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
414 if (!i2c_tuner)
415 return 0;
416
417 if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
418 i2c_tuner)) {
419 err("CX24113 could NOT be attached");
420 return 0;
421 }
422 info("CX24113 successfully attached");
423
424 fc->fc_i2c_adap[2].no_base_addr = 1;
425 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
426 0x08, 0, 0)) {
427 err("ISL6421 could NOT be attached");
428 fc->fc_i2c_adap[2].no_base_addr = 0;
429 return 0;
430 }
431 info("ISL6421 successfully attached");
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300432 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
433 * IR-receiver (PIC16F818) - but the card has no input for that ??? */
Trent Piephoeccd15a2009-06-11 05:33:00 -0300434 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300435}
436#endif
437
438/* AirStar DVB-T */
439#if defined(CONFIG_DVB_MT352_MODULE)
440static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
441{
442 static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
443 static u8 mt352_reset[] = { 0x50, 0x80 };
444 static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
445 static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
446 static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
447
448 mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
449 udelay(2000);
450 mt352_write(fe, mt352_reset, sizeof(mt352_reset));
451 mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
452 mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
453 mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
454 return 0;
455}
456
457static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
458 struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
459{
460 u32 div;
461 unsigned char bs = 0;
462
463 if (buf_len < 5)
464 return -EINVAL;
465
466#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
467 div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
468 if (params->frequency >= 48000000 && params->frequency <= 154000000) \
469 bs = 0x09;
470 if (params->frequency >= 161000000 && params->frequency <= 439000000) \
471 bs = 0x0a;
472 if (params->frequency >= 447000000 && params->frequency <= 863000000) \
473 bs = 0x08;
474
475 pllbuf[0] = 0x61;
476 pllbuf[1] = div >> 8;
477 pllbuf[2] = div & 0xff;
478 pllbuf[3] = 0xcc;
479 pllbuf[4] = bs;
480 return 5;
481}
482
483static struct mt352_config samsung_tdtc9251dh0_config = {
484 .demod_address = 0x0f,
485 .demod_init = samsung_tdtc9251dh0_demod_init,
486};
487
Trent Piephoeccd15a2009-06-11 05:33:00 -0300488static int airstar_dvbt_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300489 struct i2c_adapter *i2c)
490{
491 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300492 if (fc->fe != NULL) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300493 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300494 return 1;
495 }
496 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300497}
498#endif
499
500/* AirStar ATSC 1st generation */
501#if defined(CONFIG_DVB_BCM3510_MODULE)
502static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
503 const struct firmware **fw, char* name)
504{
505 struct flexcop_device *fc = fe->dvb->priv;
506 return request_firmware(fw, name, fc->dev);
507}
508
509static struct bcm3510_config air2pc_atsc_first_gen_config = {
510 .demod_address = 0x0f,
511 .request_firmware = flexcop_fe_request_firmware,
512};
513
Trent Piephoeccd15a2009-06-11 05:33:00 -0300514static int airstar_atsc1_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300515 struct i2c_adapter *i2c)
516{
517 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300518 return fc->fe != NULL;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300519}
520#endif
521
522/* AirStar ATSC 2nd generation */
523#if defined(CONFIG_DVB_NXT200X_MODULE)
524static struct nxt200x_config samsung_tbmv_config = {
525 .demod_address = 0x0a,
526};
527
Trent Piephoeccd15a2009-06-11 05:33:00 -0300528static int airstar_atsc2_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300529 struct i2c_adapter *i2c)
530{
531 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300532 if (!fc->fe)
533 return 0;
534
535 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
536 DVB_PLL_SAMSUNG_TBMV);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300537}
538#endif
539
540/* AirStar ATSC 3rd generation */
541#if defined(CONFIG_DVB_LGDT330X_MODULE)
542static struct lgdt330x_config air2pc_atsc_hd5000_config = {
543 .demod_address = 0x59,
544 .demod_chip = LGDT3303,
545 .serial_mpeg = 0x04,
546 .clock_polarity_flip = 1,
547};
548
Trent Piephoeccd15a2009-06-11 05:33:00 -0300549static int airstar_atsc3_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300550 struct i2c_adapter *i2c)
551{
552 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300553 if (!fc->fe)
554 return 0;
555
556 return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
557 TUNER_LG_TDVS_H06XF);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300558}
559#endif
560
561/* CableStar2 DVB-C */
562#if defined(CONFIG_DVB_STV0297_MODULE)
Adrian Bunkdd00b1e2006-05-29 12:31:44 -0300563static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300564 struct dvb_frontend_parameters *fep)
Andrew de Quincey56e03142006-04-18 17:47:12 -0300565{
566 struct flexcop_device *fc = fe->dvb->priv;
567 u8 buf[4];
568 u16 div;
569 int ret;
570
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300571/* 62.5 kHz * 10 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300572#define REF_FREQ 625
573#define FREQ_OFFSET 36125
574
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300575 div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
576/* 4 MHz = 4000 KHz */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300577
578 buf[0] = (u8)( div >> 8) & 0x7f;
579 buf[1] = (u8) div & 0xff;
580
581/* F(osc) = N * Reference Freq. (62.5 kHz)
582 * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
583 * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
584 * byte 4 : 1 * * AGD R3 R2 R1 R0
585 * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
586 * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
587 buf[2] = 0x95;
588
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300589/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
590 * 47 - 153 0 * 0 0 0 0 0 1 0x01
591 * 153 - 430 0 * 0 0 0 0 1 0 0x02
592 * 430 - 822 0 * 0 0 1 0 0 0 0x08
593 * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300594
595 if (fep->frequency <= 153000000) buf[3] = 0x01;
596 else if (fep->frequency <= 430000000) buf[3] = 0x02;
597 else if (fep->frequency <= 822000000) buf[3] = 0x08;
598 else buf[3] = 0x88;
599
Patrick Boettcherdea74862006-05-14 05:01:31 -0300600 if (fe->ops.i2c_gate_ctrl)
Antti Seppälä9d85d772006-12-20 11:10:35 -0300601 fe->ops.i2c_gate_ctrl(fe, 0);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300602 deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
603 buf[0], buf[1], buf[2], buf[3]);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300604 ret = fc->i2c_request(&fc->fc_i2c_adap[2],
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300605 FC_WRITE, 0x61, buf[0], &buf[1], 3);
Andrew de Quincey56e03142006-04-18 17:47:12 -0300606 deb_tuner("tuner write returned: %d\n",ret);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300607 return ret;
Andrew de Quincey56e03142006-04-18 17:47:12 -0300608}
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700609
610static u8 alps_tdee4_stv0297_inittab[] = {
611 0x80, 0x01,
612 0x80, 0x00,
613 0x81, 0x01,
614 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300615 0x00, 0x48,
616 0x01, 0x58,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700617 0x03, 0x00,
618 0x04, 0x00,
619 0x07, 0x00,
620 0x08, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700621 0x30, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300622 0x31, 0x9d,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700623 0x32, 0xff,
624 0x33, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300625 0x34, 0x29,
626 0x35, 0x55,
627 0x36, 0x80,
628 0x37, 0x6e,
629 0x38, 0x9c,
630 0x40, 0x1a,
631 0x41, 0xfe,
632 0x42, 0x33,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700633 0x43, 0x00,
634 0x44, 0xff,
635 0x45, 0x00,
636 0x46, 0x00,
637 0x49, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300638 0x4a, 0x51,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700639 0x4b, 0xf8,
640 0x52, 0x30,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300641 0x53, 0x06,
642 0x59, 0x06,
643 0x5a, 0x5e,
644 0x5b, 0x04,
645 0x61, 0x49,
646 0x62, 0x0a,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700647 0x70, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300648 0x71, 0x04,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700649 0x72, 0x00,
650 0x73, 0x00,
651 0x74, 0x0c,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300652 0x80, 0x20,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700653 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300654 0x82, 0x30,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700655 0x83, 0x00,
656 0x84, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300657 0x85, 0x22,
658 0x86, 0x08,
659 0x87, 0x1b,
660 0x88, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700661 0x89, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300662 0x90, 0x00,
663 0x91, 0x04,
664 0xa0, 0x86,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700665 0xa1, 0x00,
666 0xa2, 0x00,
667 0xb0, 0x91,
668 0xb1, 0x0b,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300669 0xc0, 0x5b,
670 0xc1, 0x10,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700671 0xc2, 0x12,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300672 0xd0, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700673 0xd1, 0x00,
674 0xd2, 0x00,
675 0xd3, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300676 0xd4, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700677 0xd5, 0x00,
678 0xde, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300679 0xdf, 0x01,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700680 0xff, 0xff,
681};
682
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700683static struct stv0297_config alps_tdee4_stv0297_config = {
684 .demod_address = 0x1c,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700685 .inittab = alps_tdee4_stv0297_inittab,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700686};
687
Trent Piephoeccd15a2009-06-11 05:33:00 -0300688static int cablestar2_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300689 struct i2c_adapter *i2c)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700690{
Antti Seppälä11c6c7f2008-12-01 06:59:37 -0300691 fc->fc_i2c_adap[0].no_base_addr = 1;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300692 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300693 if (!fc->fe) {
694 /* Reset for next frontend to try */
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300695 fc->fc_i2c_adap[0].no_base_addr = 0;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300696 return 0;
697 }
698 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
699 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300700}
701#endif
702
703static struct {
704 flexcop_device_type_t type;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300705 int (*attach)(struct flexcop_device *, struct i2c_adapter *);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300706} flexcop_frontends[] = {
707#if defined(CONFIG_DVB_S5H1420_MODULE)
708 { FC_SKY_REV27, skystar2_rev27_attach },
709#endif
710#if defined(CONFIG_DVB_CX24123_MODULE)
711 { FC_SKY_REV28, skystar2_rev28_attach },
712#endif
713#if defined(CONFIG_DVB_STV0299_MODULE)
714 { FC_SKY_REV26, skystar2_rev26_attach },
715#endif
716#if defined(CONFIG_DVB_MT352_MODULE)
717 { FC_AIR_DVBT, airstar_dvbt_attach },
718#endif
719#if defined(CONFIG_DVB_NXT200X_MODULE)
720 { FC_AIR_ATSC2, airstar_atsc2_attach },
721#endif
722#if defined(CONFIG_DVB_LGDT330X_MODULE)
723 { FC_AIR_ATSC3, airstar_atsc3_attach },
724#endif
725#if defined(CONFIG_DVB_BCM3510_MODULE)
726 { FC_AIR_ATSC1, airstar_atsc1_attach },
727#endif
728#if defined(CONFIG_DVB_STV0297_MODULE)
729 { FC_CABLE, cablestar2_attach },
730#endif
731#if defined(CONFIG_DVB_MT312_MODULE)
732 { FC_SKY_REV23, skystar2_rev23_attach },
733#endif
734};
735
736/* try to figure out the frontend */
737int flexcop_frontend_init(struct flexcop_device *fc)
738{
739 int i;
740 for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
741 /* type needs to be set before, because of some workarounds
742 * done based on the probed card type */
743 fc->dev_type = flexcop_frontends[i].type;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300744 if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300745 goto fe_found;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300746 /* Clean up partially attached frontend */
747 if (fc->fe) {
748 dvb_frontend_detach(fc->fe);
749 fc->fe = NULL;
750 }
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300751 }
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300752 fc->dev_type = FC_UNK;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300753 err("no frontend driver found for this B2C2/FlexCop adapter");
754 return -ENODEV;
755
756fe_found:
757 info("found '%s' .", fc->fe->ops.info.name);
758 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
759 err("frontend registration failed!");
Trent Piephoeccd15a2009-06-11 05:33:00 -0300760 dvb_frontend_detach(fc->fe);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300761 fc->fe = NULL;
762 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700763 }
764 fc->init_state |= FC_STATE_FE_INIT;
765 return 0;
766}
767
768void flexcop_frontend_exit(struct flexcop_device *fc)
769{
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300770 if (fc->init_state & FC_STATE_FE_INIT) {
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700771 dvb_unregister_frontend(fc->fe);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -0300772 dvb_frontend_detach(fc->fe);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300773 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700774 fc->init_state &= ~FC_STATE_FE_INIT;
775}