blob: 9a6307a347b21e7169a41f4f4a9d1ecbce15dd3f [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
Trent Piepho68b7f762009-06-11 19:31:22 -030023
24/* Can we use the specified front-end? Remember that if we are compiled
25 * into the kernel we can't call code that's in modules. */
26#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
27 (defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
28
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070029/* lnb control */
Trent Piepho68b7f762009-06-11 19:31:22 -030030#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070031static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
32{
33 struct flexcop_device *fc = fe->dvb->priv;
34 flexcop_ibi_value v;
35 deb_tuner("polarity/voltage = %u\n", voltage);
36
37 v = fc->read_ibi_reg(fc, misc_204);
38 switch (voltage) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030039 case SEC_VOLTAGE_OFF:
40 v.misc_204.ACPI1_sig = 1;
41 break;
42 case SEC_VOLTAGE_13:
43 v.misc_204.ACPI1_sig = 0;
44 v.misc_204.LNB_L_H_sig = 0;
45 break;
46 case SEC_VOLTAGE_18:
47 v.misc_204.ACPI1_sig = 0;
48 v.misc_204.LNB_L_H_sig = 1;
49 break;
50 default:
51 err("unknown SEC_VOLTAGE value");
52 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070053 }
54 return fc->write_ibi_reg(fc, misc_204, v);
55}
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030056#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070057
Trent Piepho68b7f762009-06-11 19:31:22 -030058#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070059static int flexcop_sleep(struct dvb_frontend* fe)
60{
61 struct flexcop_device *fc = fe->dvb->priv;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070062 if (fc->fe_sleep)
63 return fc->fe_sleep(fe);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070064 return 0;
65}
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030066#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070067
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030068/* SkyStar2 DVB-S rev 2.3 */
Trent Piepho68b7f762009-06-11 19:31:22 -030069#if FE_SUPPORTED(MT312)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070070static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
71{
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030072/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070073 struct flexcop_device *fc = fe->dvb->priv;
74 flexcop_ibi_value v;
75 u16 ax;
76 v.raw = 0;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070077 deb_tuner("tone = %u\n",tone);
78
79 switch (tone) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -030080 case SEC_TONE_ON:
81 ax = 0x01ff;
82 break;
83 case SEC_TONE_OFF:
84 ax = 0;
85 break;
86 default:
87 err("unknown SEC_TONE value");
88 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070089 }
90
91 v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
Johannes Stezenbach958706c2005-05-16 21:54:19 -070092 v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
93 v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -070094 return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
95}
96
97static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
98{
99 flexcop_set_tone(fe, SEC_TONE_ON);
100 udelay(data ? 500 : 1000);
101 flexcop_set_tone(fe, SEC_TONE_OFF);
102 udelay(data ? 1000 : 500);
103}
104
105static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
106{
107 int i, par = 1, d;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700108 for (i = 7; i >= 0; i--) {
109 d = (data >> i) & 1;
110 par ^= d;
111 flexcop_diseqc_send_bit(fe, d);
112 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700113 flexcop_diseqc_send_bit(fe, par);
114}
115
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300116static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
117 int len, u8 *msg, unsigned long burst)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700118{
119 int i;
120
121 flexcop_set_tone(fe, SEC_TONE_OFF);
122 mdelay(16);
123
124 for (i = 0; i < len; i++)
125 flexcop_diseqc_send_byte(fe,msg[i]);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700126 mdelay(16);
127
128 if (burst != -1) {
129 if (burst)
130 flexcop_diseqc_send_byte(fe, 0xff);
131 else {
132 flexcop_set_tone(fe, SEC_TONE_ON);
Thierry MERLEc4e3fd92008-09-01 17:32:10 -0300133 mdelay(12);
134 udelay(500);
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700135 flexcop_set_tone(fe, SEC_TONE_OFF);
136 }
137 msleep(20);
138 }
139 return 0;
140}
141
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300142static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
143 struct dvb_diseqc_master_cmd *cmd)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700144{
145 return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
146}
147
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300148static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
149 fe_sec_mini_cmd_t minicmd)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700150{
151 return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
152}
153
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300154static struct mt312_config skystar23_samsung_tbdu18132_config = {
155 .demod_address = 0x0e,
156};
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700157
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300158static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend *fe,
159 struct dvb_frontend_parameters *params)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700160{
161 u8 buf[4];
162 u32 div;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300163 struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf,
164 .len = sizeof(buf) };
Andrew de Quincey56e03142006-04-18 17:47:12 -0300165 struct flexcop_device *fc = fe->dvb->priv;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700166 div = (params->frequency + (125/2)) / 125;
167
168 buf[0] = (div >> 8) & 0x7f;
169 buf[1] = (div >> 0) & 0xff;
170 buf[2] = 0x84 | ((div >> 10) & 0x60);
171 buf[3] = 0x80;
172
173 if (params->frequency < 1550000)
174 buf[3] |= 0x02;
175
Patrick Boettcherdea74862006-05-14 05:01:31 -0300176 if (fe->ops.i2c_gate_ctrl)
177 fe->ops.i2c_gate_ctrl(fe, 1);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300178 if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700179 return -EIO;
180 return 0;
181}
182
Trent Piephoeccd15a2009-06-11 05:33:00 -0300183static int skystar2_rev23_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300184 struct i2c_adapter *i2c)
185{
Trent Piephoeccd15a2009-06-11 05:33:00 -0300186 fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300187 if (fc->fe != NULL) {
188 struct dvb_frontend_ops *ops = &fc->fe->ops;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300189 ops->tuner_ops.set_params =
190 skystar23_samsung_tbdu18132_tuner_set_params;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300191 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
192 ops->diseqc_send_burst = flexcop_diseqc_send_burst;
193 ops->set_tone = flexcop_set_tone;
194 ops->set_voltage = flexcop_set_voltage;
195 fc->fe_sleep = ops->sleep;
196 ops->sleep = flexcop_sleep;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300197 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300198 }
Trent Piephoeccd15a2009-06-11 05:33:00 -0300199 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300200}
Trent Piepho68b7f762009-06-11 19:31:22 -0300201#else
202#define skystar2_rev23_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300203#endif
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700204
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300205/* SkyStar2 DVB-S rev 2.6 */
Trent Piepho68b7f762009-06-11 19:31:22 -0300206#if FE_SUPPORTED(STV0299)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300207static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
208 u32 srate, u32 ratio)
209{
210 u8 aclk = 0;
211 u8 bclk = 0;
212
213 if (srate < 1500000) {
214 aclk = 0xb7; bclk = 0x47;
215 } else if (srate < 3000000) {
216 aclk = 0xb7; bclk = 0x4b;
217 } else if (srate < 7000000) {
218 aclk = 0xb7; bclk = 0x4f;
219 } else if (srate < 14000000) {
220 aclk = 0xb7; bclk = 0x53;
221 } else if (srate < 30000000) {
222 aclk = 0xb6; bclk = 0x53;
223 } else if (srate < 45000000) {
224 aclk = 0xb4; bclk = 0x51;
225 }
226
227 stv0299_writereg(fe, 0x13, aclk);
228 stv0299_writereg(fe, 0x14, bclk);
229 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
230 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
231 stv0299_writereg(fe, 0x21, ratio & 0xf0);
232 return 0;
233}
234
235static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend *fe,
236 struct dvb_frontend_parameters *params)
237{
238 u8 buf[4];
239 u32 div;
240 struct i2c_msg msg = {
241 .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
242 struct flexcop_device *fc = fe->dvb->priv;
243 div = params->frequency / 125;
244
245 buf[0] = (div >> 8) & 0x7f;
246 buf[1] = div & 0xff;
247 buf[2] = 0x84; /* 0xC4 */
248 buf[3] = 0x08;
249
250 if (params->frequency < 1500000)
251 buf[3] |= 0x10;
252
253 if (fe->ops.i2c_gate_ctrl)
254 fe->ops.i2c_gate_ctrl(fe, 1);
255 if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
256 return -EIO;
257 return 0;
258}
259
260static u8 samsung_tbmu24112_inittab[] = {
261 0x01, 0x15,
262 0x02, 0x30,
263 0x03, 0x00,
264 0x04, 0x7D,
265 0x05, 0x35,
266 0x06, 0x02,
267 0x07, 0x00,
268 0x08, 0xC3,
269 0x0C, 0x00,
270 0x0D, 0x81,
271 0x0E, 0x23,
272 0x0F, 0x12,
273 0x10, 0x7E,
274 0x11, 0x84,
275 0x12, 0xB9,
276 0x13, 0x88,
277 0x14, 0x89,
278 0x15, 0xC9,
279 0x16, 0x00,
280 0x17, 0x5C,
281 0x18, 0x00,
282 0x19, 0x00,
283 0x1A, 0x00,
284 0x1C, 0x00,
285 0x1D, 0x00,
286 0x1E, 0x00,
287 0x1F, 0x3A,
288 0x20, 0x2E,
289 0x21, 0x80,
290 0x22, 0xFF,
291 0x23, 0xC1,
292 0x28, 0x00,
293 0x29, 0x1E,
294 0x2A, 0x14,
295 0x2B, 0x0F,
296 0x2C, 0x09,
297 0x2D, 0x05,
298 0x31, 0x1F,
299 0x32, 0x19,
300 0x33, 0xFE,
301 0x34, 0x93,
302 0xff, 0xff,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700303};
304
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300305static struct stv0299_config samsung_tbmu24112_config = {
306 .demod_address = 0x68,
307 .inittab = samsung_tbmu24112_inittab,
308 .mclk = 88000000UL,
309 .invert = 0,
310 .skip_reinit = 0,
311 .lock_output = STV0299_LOCKOUTPUT_LK,
312 .volt13_op0_op1 = STV0299_VOLT13_OP1,
313 .min_delay_ms = 100,
314 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
315};
316
Trent Piephoeccd15a2009-06-11 05:33:00 -0300317static int skystar2_rev26_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300318 struct i2c_adapter *i2c)
319{
320 fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
321 if (fc->fe != NULL) {
322 struct dvb_frontend_ops *ops = &fc->fe->ops;
323 ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
324 ops->set_voltage = flexcop_set_voltage;
325 fc->fe_sleep = ops->sleep;
326 ops->sleep = flexcop_sleep;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300327 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300328 }
Trent Piephoeccd15a2009-06-11 05:33:00 -0300329 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300330}
Trent Piepho68b7f762009-06-11 19:31:22 -0300331#else
332#define skystar2_rev26_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300333#endif
334
335/* SkyStar2 DVB-S rev 2.7 */
Trent Piepho68b7f762009-06-11 19:31:22 -0300336#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300337static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
338 .demod_address = 0x53,
339 .invert = 1,
340 .repeated_start_workaround = 1,
341 .serial_mpeg = 1,
342};
343
344static struct itd1000_config skystar2_rev2_7_itd1000_config = {
345 .i2c_address = 0x61,
346};
347
Trent Piephoeccd15a2009-06-11 05:33:00 -0300348static int skystar2_rev27_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300349 struct i2c_adapter *i2c)
350{
Trent Piephoeccd15a2009-06-11 05:33:00 -0300351 flexcop_ibi_value r108;
352 struct i2c_adapter *i2c_tuner;
353
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300354 /* enable no_base_addr - no repeated start when reading */
355 fc->fc_i2c_adap[0].no_base_addr = 1;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300356 fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
357 i2c);
358 if (!fc->fe)
359 goto fail;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300360
Trent Piephoeccd15a2009-06-11 05:33:00 -0300361 i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
362 if (!i2c_tuner)
363 goto fail;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300364
Trent Piephoeccd15a2009-06-11 05:33:00 -0300365 fc->fe_sleep = fc->fe->ops.sleep;
366 fc->fe->ops.sleep = flexcop_sleep;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300367
Trent Piephoeccd15a2009-06-11 05:33:00 -0300368 /* enable no_base_addr - no repeated start when reading */
369 fc->fc_i2c_adap[2].no_base_addr = 1;
370 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
371 0x08, 1, 1)) {
372 err("ISL6421 could NOT be attached");
373 goto fail_isl;
374 }
375 info("ISL6421 successfully attached");
376
377 /* the ITD1000 requires a lower i2c clock - is it a problem ? */
378 r108.raw = 0x00000506;
379 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
380 if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
381 &skystar2_rev2_7_itd1000_config)) {
382 err("ITD1000 could NOT be attached");
383 /* Should i2c clock be restored? */
384 goto fail_isl;
385 }
386 info("ITD1000 successfully attached");
387
388 return 1;
389
390fail_isl:
391 fc->fc_i2c_adap[2].no_base_addr = 0;
392fail:
393 /* for the next devices we need it again */
394 fc->fc_i2c_adap[0].no_base_addr = 0;
395 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300396}
Trent Piepho68b7f762009-06-11 19:31:22 -0300397#else
398#define skystar2_rev27_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300399#endif
400
401/* SkyStar2 rev 2.8 */
Trent Piepho68b7f762009-06-11 19:31:22 -0300402#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300403static struct cx24123_config skystar2_rev2_8_cx24123_config = {
404 .demod_address = 0x55,
405 .dont_use_pll = 1,
406 .agc_callback = cx24113_agc_callback,
407};
408
409static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
410 .i2c_addr = 0x54,
411 .xtal_khz = 10111,
412};
413
Trent Piephoeccd15a2009-06-11 05:33:00 -0300414static int skystar2_rev28_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300415 struct i2c_adapter *i2c)
416{
Trent Piephoeccd15a2009-06-11 05:33:00 -0300417 struct i2c_adapter *i2c_tuner;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300418
Trent Piephoeccd15a2009-06-11 05:33:00 -0300419 fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
420 i2c);
421 if (!fc->fe)
422 return 0;
423
424 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);;
425 if (!i2c_tuner)
426 return 0;
427
428 if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
429 i2c_tuner)) {
430 err("CX24113 could NOT be attached");
431 return 0;
432 }
433 info("CX24113 successfully attached");
434
435 fc->fc_i2c_adap[2].no_base_addr = 1;
436 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
437 0x08, 0, 0)) {
438 err("ISL6421 could NOT be attached");
439 fc->fc_i2c_adap[2].no_base_addr = 0;
440 return 0;
441 }
442 info("ISL6421 successfully attached");
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300443 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
444 * IR-receiver (PIC16F818) - but the card has no input for that ??? */
Trent Piephoeccd15a2009-06-11 05:33:00 -0300445 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300446}
Trent Piepho68b7f762009-06-11 19:31:22 -0300447#else
448#define skystar2_rev28_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300449#endif
450
451/* AirStar DVB-T */
Trent Piepho68b7f762009-06-11 19:31:22 -0300452#if FE_SUPPORTED(MT352)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300453static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
454{
455 static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
456 static u8 mt352_reset[] = { 0x50, 0x80 };
457 static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
458 static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
459 static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
460
461 mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
462 udelay(2000);
463 mt352_write(fe, mt352_reset, sizeof(mt352_reset));
464 mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
465 mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
466 mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
467 return 0;
468}
469
470static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend *fe,
471 struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
472{
473 u32 div;
474 unsigned char bs = 0;
475
476 if (buf_len < 5)
477 return -EINVAL;
478
479#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
480 div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
481 if (params->frequency >= 48000000 && params->frequency <= 154000000) \
482 bs = 0x09;
483 if (params->frequency >= 161000000 && params->frequency <= 439000000) \
484 bs = 0x0a;
485 if (params->frequency >= 447000000 && params->frequency <= 863000000) \
486 bs = 0x08;
487
488 pllbuf[0] = 0x61;
489 pllbuf[1] = div >> 8;
490 pllbuf[2] = div & 0xff;
491 pllbuf[3] = 0xcc;
492 pllbuf[4] = bs;
493 return 5;
494}
495
496static struct mt352_config samsung_tdtc9251dh0_config = {
497 .demod_address = 0x0f,
498 .demod_init = samsung_tdtc9251dh0_demod_init,
499};
500
Trent Piephoeccd15a2009-06-11 05:33:00 -0300501static int airstar_dvbt_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300502 struct i2c_adapter *i2c)
503{
504 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300505 if (fc->fe != NULL) {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300506 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300507 return 1;
508 }
509 return 0;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300510}
Trent Piepho68b7f762009-06-11 19:31:22 -0300511#else
512#define airstar_dvbt_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300513#endif
514
515/* AirStar ATSC 1st generation */
Trent Piepho68b7f762009-06-11 19:31:22 -0300516#if FE_SUPPORTED(BCM3510)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300517static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
518 const struct firmware **fw, char* name)
519{
520 struct flexcop_device *fc = fe->dvb->priv;
521 return request_firmware(fw, name, fc->dev);
522}
523
524static struct bcm3510_config air2pc_atsc_first_gen_config = {
525 .demod_address = 0x0f,
526 .request_firmware = flexcop_fe_request_firmware,
527};
528
Trent Piephoeccd15a2009-06-11 05:33:00 -0300529static int airstar_atsc1_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300530 struct i2c_adapter *i2c)
531{
532 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300533 return fc->fe != NULL;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300534}
Trent Piepho68b7f762009-06-11 19:31:22 -0300535#else
536#define airstar_atsc1_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300537#endif
538
539/* AirStar ATSC 2nd generation */
Trent Piepho68b7f762009-06-11 19:31:22 -0300540#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300541static struct nxt200x_config samsung_tbmv_config = {
542 .demod_address = 0x0a,
543};
544
Trent Piephoeccd15a2009-06-11 05:33:00 -0300545static int airstar_atsc2_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300546 struct i2c_adapter *i2c)
547{
548 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300549 if (!fc->fe)
550 return 0;
551
552 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
553 DVB_PLL_SAMSUNG_TBMV);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300554}
Trent Piepho68b7f762009-06-11 19:31:22 -0300555#else
556#define airstar_atsc2_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300557#endif
558
559/* AirStar ATSC 3rd generation */
Trent Piepho68b7f762009-06-11 19:31:22 -0300560#if FE_SUPPORTED(LGDT330X)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300561static struct lgdt330x_config air2pc_atsc_hd5000_config = {
562 .demod_address = 0x59,
563 .demod_chip = LGDT3303,
564 .serial_mpeg = 0x04,
565 .clock_polarity_flip = 1,
566};
567
Trent Piephoeccd15a2009-06-11 05:33:00 -0300568static int airstar_atsc3_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300569 struct i2c_adapter *i2c)
570{
571 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300572 if (!fc->fe)
573 return 0;
574
575 return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
576 TUNER_LG_TDVS_H06XF);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300577}
Trent Piepho68b7f762009-06-11 19:31:22 -0300578#else
579#define airstar_atsc3_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300580#endif
581
582/* CableStar2 DVB-C */
Trent Piepho68b7f762009-06-11 19:31:22 -0300583#if FE_SUPPORTED(STV0297)
Adrian Bunkdd00b1e2006-05-29 12:31:44 -0300584static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300585 struct dvb_frontend_parameters *fep)
Andrew de Quincey56e03142006-04-18 17:47:12 -0300586{
587 struct flexcop_device *fc = fe->dvb->priv;
588 u8 buf[4];
589 u16 div;
590 int ret;
591
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300592/* 62.5 kHz * 10 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300593#define REF_FREQ 625
594#define FREQ_OFFSET 36125
595
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300596 div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
597/* 4 MHz = 4000 KHz */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300598
599 buf[0] = (u8)( div >> 8) & 0x7f;
600 buf[1] = (u8) div & 0xff;
601
602/* F(osc) = N * Reference Freq. (62.5 kHz)
603 * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
604 * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
605 * byte 4 : 1 * * AGD R3 R2 R1 R0
606 * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
607 * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
608 buf[2] = 0x95;
609
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300610/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
611 * 47 - 153 0 * 0 0 0 0 0 1 0x01
612 * 153 - 430 0 * 0 0 0 0 1 0 0x02
613 * 430 - 822 0 * 0 0 1 0 0 0 0x08
614 * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300615
616 if (fep->frequency <= 153000000) buf[3] = 0x01;
617 else if (fep->frequency <= 430000000) buf[3] = 0x02;
618 else if (fep->frequency <= 822000000) buf[3] = 0x08;
619 else buf[3] = 0x88;
620
Patrick Boettcherdea74862006-05-14 05:01:31 -0300621 if (fe->ops.i2c_gate_ctrl)
Antti Seppälä9d85d772006-12-20 11:10:35 -0300622 fe->ops.i2c_gate_ctrl(fe, 0);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300623 deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
624 buf[0], buf[1], buf[2], buf[3]);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300625 ret = fc->i2c_request(&fc->fc_i2c_adap[2],
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300626 FC_WRITE, 0x61, buf[0], &buf[1], 3);
Andrew de Quincey56e03142006-04-18 17:47:12 -0300627 deb_tuner("tuner write returned: %d\n",ret);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300628 return ret;
Andrew de Quincey56e03142006-04-18 17:47:12 -0300629}
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700630
631static u8 alps_tdee4_stv0297_inittab[] = {
632 0x80, 0x01,
633 0x80, 0x00,
634 0x81, 0x01,
635 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300636 0x00, 0x48,
637 0x01, 0x58,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700638 0x03, 0x00,
639 0x04, 0x00,
640 0x07, 0x00,
641 0x08, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700642 0x30, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300643 0x31, 0x9d,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700644 0x32, 0xff,
645 0x33, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300646 0x34, 0x29,
647 0x35, 0x55,
648 0x36, 0x80,
649 0x37, 0x6e,
650 0x38, 0x9c,
651 0x40, 0x1a,
652 0x41, 0xfe,
653 0x42, 0x33,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700654 0x43, 0x00,
655 0x44, 0xff,
656 0x45, 0x00,
657 0x46, 0x00,
658 0x49, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300659 0x4a, 0x51,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700660 0x4b, 0xf8,
661 0x52, 0x30,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300662 0x53, 0x06,
663 0x59, 0x06,
664 0x5a, 0x5e,
665 0x5b, 0x04,
666 0x61, 0x49,
667 0x62, 0x0a,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700668 0x70, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300669 0x71, 0x04,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700670 0x72, 0x00,
671 0x73, 0x00,
672 0x74, 0x0c,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300673 0x80, 0x20,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700674 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300675 0x82, 0x30,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700676 0x83, 0x00,
677 0x84, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300678 0x85, 0x22,
679 0x86, 0x08,
680 0x87, 0x1b,
681 0x88, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700682 0x89, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300683 0x90, 0x00,
684 0x91, 0x04,
685 0xa0, 0x86,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700686 0xa1, 0x00,
687 0xa2, 0x00,
688 0xb0, 0x91,
689 0xb1, 0x0b,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300690 0xc0, 0x5b,
691 0xc1, 0x10,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700692 0xc2, 0x12,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300693 0xd0, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700694 0xd1, 0x00,
695 0xd2, 0x00,
696 0xd3, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300697 0xd4, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700698 0xd5, 0x00,
699 0xde, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300700 0xdf, 0x01,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700701 0xff, 0xff,
702};
703
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700704static struct stv0297_config alps_tdee4_stv0297_config = {
705 .demod_address = 0x1c,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700706 .inittab = alps_tdee4_stv0297_inittab,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700707};
708
Trent Piephoeccd15a2009-06-11 05:33:00 -0300709static int cablestar2_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300710 struct i2c_adapter *i2c)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700711{
Antti Seppälä11c6c7f2008-12-01 06:59:37 -0300712 fc->fc_i2c_adap[0].no_base_addr = 1;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300713 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300714 if (!fc->fe) {
715 /* Reset for next frontend to try */
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300716 fc->fc_i2c_adap[0].no_base_addr = 0;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300717 return 0;
718 }
719 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
720 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300721}
Trent Piepho68b7f762009-06-11 19:31:22 -0300722#else
723#define cablestar2_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300724#endif
725
726static struct {
727 flexcop_device_type_t type;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300728 int (*attach)(struct flexcop_device *, struct i2c_adapter *);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300729} flexcop_frontends[] = {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300730 { FC_SKY_REV27, skystar2_rev27_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300731 { FC_SKY_REV28, skystar2_rev28_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300732 { FC_SKY_REV26, skystar2_rev26_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300733 { FC_AIR_DVBT, airstar_dvbt_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300734 { FC_AIR_ATSC2, airstar_atsc2_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300735 { FC_AIR_ATSC3, airstar_atsc3_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300736 { FC_AIR_ATSC1, airstar_atsc1_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300737 { FC_CABLE, cablestar2_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300738 { FC_SKY_REV23, skystar2_rev23_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300739};
740
741/* try to figure out the frontend */
742int flexcop_frontend_init(struct flexcop_device *fc)
743{
744 int i;
745 for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
Trent Piepho68b7f762009-06-11 19:31:22 -0300746 if (!flexcop_frontends[i].attach)
747 continue;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300748 /* type needs to be set before, because of some workarounds
749 * done based on the probed card type */
750 fc->dev_type = flexcop_frontends[i].type;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300751 if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300752 goto fe_found;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300753 /* Clean up partially attached frontend */
754 if (fc->fe) {
755 dvb_frontend_detach(fc->fe);
756 fc->fe = NULL;
757 }
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300758 }
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300759 fc->dev_type = FC_UNK;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300760 err("no frontend driver found for this B2C2/FlexCop adapter");
761 return -ENODEV;
762
763fe_found:
764 info("found '%s' .", fc->fe->ops.info.name);
765 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
766 err("frontend registration failed!");
Trent Piephoeccd15a2009-06-11 05:33:00 -0300767 dvb_frontend_detach(fc->fe);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300768 fc->fe = NULL;
769 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700770 }
771 fc->init_state |= FC_STATE_FE_INIT;
772 return 0;
773}
774
775void flexcop_frontend_exit(struct flexcop_device *fc)
776{
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300777 if (fc->init_state & FC_STATE_FE_INIT) {
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700778 dvb_unregister_frontend(fc->fe);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -0300779 dvb_frontend_detach(fc->fe);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300780 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700781 fc->init_state &= ~FC_STATE_FE_INIT;
782}