blob: c35661a5ab278ace41ae465283e8b8bf5c771dc0 [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
Joe Perches1ebcad72009-07-02 15:57:09 -0300424 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300425 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 Piepho6d67c972009-06-11 19:31:22 -0300452#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
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
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300470static struct mt352_config samsung_tdtc9251dh0_config = {
471 .demod_address = 0x0f,
472 .demod_init = samsung_tdtc9251dh0_demod_init,
473};
474
Trent Piephoeccd15a2009-06-11 05:33:00 -0300475static int airstar_dvbt_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300476 struct i2c_adapter *i2c)
477{
478 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
Trent Piepho6d67c972009-06-11 19:31:22 -0300479 if (!fc->fe)
480 return 0;
481
482 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
483 DVB_PLL_SAMSUNG_TDTC9251DH0);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300484}
Trent Piepho68b7f762009-06-11 19:31:22 -0300485#else
486#define airstar_dvbt_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300487#endif
488
489/* AirStar ATSC 1st generation */
Trent Piepho68b7f762009-06-11 19:31:22 -0300490#if FE_SUPPORTED(BCM3510)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300491static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
492 const struct firmware **fw, char* name)
493{
494 struct flexcop_device *fc = fe->dvb->priv;
495 return request_firmware(fw, name, fc->dev);
496}
497
498static struct bcm3510_config air2pc_atsc_first_gen_config = {
499 .demod_address = 0x0f,
500 .request_firmware = flexcop_fe_request_firmware,
501};
502
Trent Piephoeccd15a2009-06-11 05:33:00 -0300503static int airstar_atsc1_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300504 struct i2c_adapter *i2c)
505{
506 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300507 return fc->fe != NULL;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300508}
Trent Piepho68b7f762009-06-11 19:31:22 -0300509#else
510#define airstar_atsc1_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300511#endif
512
513/* AirStar ATSC 2nd generation */
Trent Piepho68b7f762009-06-11 19:31:22 -0300514#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300515static struct nxt200x_config samsung_tbmv_config = {
516 .demod_address = 0x0a,
517};
518
Trent Piephoeccd15a2009-06-11 05:33:00 -0300519static int airstar_atsc2_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300520 struct i2c_adapter *i2c)
521{
522 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300523 if (!fc->fe)
524 return 0;
525
526 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
527 DVB_PLL_SAMSUNG_TBMV);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300528}
Trent Piepho68b7f762009-06-11 19:31:22 -0300529#else
530#define airstar_atsc2_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300531#endif
532
533/* AirStar ATSC 3rd generation */
Trent Piepho68b7f762009-06-11 19:31:22 -0300534#if FE_SUPPORTED(LGDT330X)
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300535static struct lgdt330x_config air2pc_atsc_hd5000_config = {
536 .demod_address = 0x59,
537 .demod_chip = LGDT3303,
538 .serial_mpeg = 0x04,
539 .clock_polarity_flip = 1,
540};
541
Trent Piephoeccd15a2009-06-11 05:33:00 -0300542static int airstar_atsc3_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300543 struct i2c_adapter *i2c)
544{
545 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300546 if (!fc->fe)
547 return 0;
548
549 return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
550 TUNER_LG_TDVS_H06XF);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300551}
Trent Piepho68b7f762009-06-11 19:31:22 -0300552#else
553#define airstar_atsc3_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300554#endif
555
556/* CableStar2 DVB-C */
Trent Piepho68b7f762009-06-11 19:31:22 -0300557#if FE_SUPPORTED(STV0297)
Adrian Bunkdd00b1e2006-05-29 12:31:44 -0300558static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300559 struct dvb_frontend_parameters *fep)
Andrew de Quincey56e03142006-04-18 17:47:12 -0300560{
561 struct flexcop_device *fc = fe->dvb->priv;
562 u8 buf[4];
563 u16 div;
564 int ret;
565
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300566/* 62.5 kHz * 10 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300567#define REF_FREQ 625
568#define FREQ_OFFSET 36125
569
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300570 div = ((fep->frequency/1000 + FREQ_OFFSET) * 10) / REF_FREQ;
571/* 4 MHz = 4000 KHz */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300572
573 buf[0] = (u8)( div >> 8) & 0x7f;
574 buf[1] = (u8) div & 0xff;
575
576/* F(osc) = N * Reference Freq. (62.5 kHz)
577 * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8
578 * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0
579 * byte 4 : 1 * * AGD R3 R2 R1 R0
580 * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1
581 * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
582 buf[2] = 0x95;
583
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300584/* Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5
585 * 47 - 153 0 * 0 0 0 0 0 1 0x01
586 * 153 - 430 0 * 0 0 0 0 1 0 0x02
587 * 430 - 822 0 * 0 0 1 0 0 0 0x08
588 * 822 - 862 1 * 0 0 1 0 0 0 0x88 */
Andrew de Quincey56e03142006-04-18 17:47:12 -0300589
590 if (fep->frequency <= 153000000) buf[3] = 0x01;
591 else if (fep->frequency <= 430000000) buf[3] = 0x02;
592 else if (fep->frequency <= 822000000) buf[3] = 0x08;
593 else buf[3] = 0x88;
594
Patrick Boettcherdea74862006-05-14 05:01:31 -0300595 if (fe->ops.i2c_gate_ctrl)
Antti Seppälä9d85d772006-12-20 11:10:35 -0300596 fe->ops.i2c_gate_ctrl(fe, 0);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300597 deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n", fep->frequency,
598 buf[0], buf[1], buf[2], buf[3]);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300599 ret = fc->i2c_request(&fc->fc_i2c_adap[2],
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300600 FC_WRITE, 0x61, buf[0], &buf[1], 3);
Andrew de Quincey56e03142006-04-18 17:47:12 -0300601 deb_tuner("tuner write returned: %d\n",ret);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300602 return ret;
Andrew de Quincey56e03142006-04-18 17:47:12 -0300603}
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700604
605static u8 alps_tdee4_stv0297_inittab[] = {
606 0x80, 0x01,
607 0x80, 0x00,
608 0x81, 0x01,
609 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300610 0x00, 0x48,
611 0x01, 0x58,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700612 0x03, 0x00,
613 0x04, 0x00,
614 0x07, 0x00,
615 0x08, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700616 0x30, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300617 0x31, 0x9d,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700618 0x32, 0xff,
619 0x33, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300620 0x34, 0x29,
621 0x35, 0x55,
622 0x36, 0x80,
623 0x37, 0x6e,
624 0x38, 0x9c,
625 0x40, 0x1a,
626 0x41, 0xfe,
627 0x42, 0x33,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700628 0x43, 0x00,
629 0x44, 0xff,
630 0x45, 0x00,
631 0x46, 0x00,
632 0x49, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300633 0x4a, 0x51,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700634 0x4b, 0xf8,
635 0x52, 0x30,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300636 0x53, 0x06,
637 0x59, 0x06,
638 0x5a, 0x5e,
639 0x5b, 0x04,
640 0x61, 0x49,
641 0x62, 0x0a,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700642 0x70, 0xff,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300643 0x71, 0x04,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700644 0x72, 0x00,
645 0x73, 0x00,
646 0x74, 0x0c,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300647 0x80, 0x20,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700648 0x81, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300649 0x82, 0x30,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700650 0x83, 0x00,
651 0x84, 0x04,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300652 0x85, 0x22,
653 0x86, 0x08,
654 0x87, 0x1b,
655 0x88, 0x00,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700656 0x89, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300657 0x90, 0x00,
658 0x91, 0x04,
659 0xa0, 0x86,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700660 0xa1, 0x00,
661 0xa2, 0x00,
662 0xb0, 0x91,
663 0xb1, 0x0b,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300664 0xc0, 0x5b,
665 0xc1, 0x10,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700666 0xc2, 0x12,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300667 0xd0, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700668 0xd1, 0x00,
669 0xd2, 0x00,
670 0xd3, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300671 0xd4, 0x02,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700672 0xd5, 0x00,
673 0xde, 0x00,
Antti Seppälä9d85d772006-12-20 11:10:35 -0300674 0xdf, 0x01,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700675 0xff, 0xff,
676};
677
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700678static struct stv0297_config alps_tdee4_stv0297_config = {
679 .demod_address = 0x1c,
Andrew de Quinceydc27a162005-09-09 13:03:07 -0700680 .inittab = alps_tdee4_stv0297_inittab,
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700681};
682
Trent Piephoeccd15a2009-06-11 05:33:00 -0300683static int cablestar2_attach(struct flexcop_device *fc,
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300684 struct i2c_adapter *i2c)
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700685{
Antti Seppälä11c6c7f2008-12-01 06:59:37 -0300686 fc->fc_i2c_adap[0].no_base_addr = 1;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300687 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
Trent Piephoeccd15a2009-06-11 05:33:00 -0300688 if (!fc->fe) {
689 /* Reset for next frontend to try */
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300690 fc->fc_i2c_adap[0].no_base_addr = 0;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300691 return 0;
692 }
693 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
694 return 1;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300695}
Trent Piepho68b7f762009-06-11 19:31:22 -0300696#else
697#define cablestar2_attach NULL
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300698#endif
699
700static struct {
701 flexcop_device_type_t type;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300702 int (*attach)(struct flexcop_device *, struct i2c_adapter *);
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300703} flexcop_frontends[] = {
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300704 { FC_SKY_REV27, skystar2_rev27_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300705 { FC_SKY_REV28, skystar2_rev28_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300706 { FC_SKY_REV26, skystar2_rev26_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300707 { FC_AIR_DVBT, airstar_dvbt_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300708 { FC_AIR_ATSC2, airstar_atsc2_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300709 { FC_AIR_ATSC3, airstar_atsc3_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300710 { FC_AIR_ATSC1, airstar_atsc1_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300711 { FC_CABLE, cablestar2_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300712 { FC_SKY_REV23, skystar2_rev23_attach },
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300713};
714
715/* try to figure out the frontend */
716int flexcop_frontend_init(struct flexcop_device *fc)
717{
718 int i;
719 for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
Trent Piepho68b7f762009-06-11 19:31:22 -0300720 if (!flexcop_frontends[i].attach)
721 continue;
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300722 /* type needs to be set before, because of some workarounds
723 * done based on the probed card type */
724 fc->dev_type = flexcop_frontends[i].type;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300725 if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300726 goto fe_found;
Trent Piephoeccd15a2009-06-11 05:33:00 -0300727 /* Clean up partially attached frontend */
728 if (fc->fe) {
729 dvb_frontend_detach(fc->fe);
730 fc->fe = NULL;
731 }
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300732 }
Patrick Boettcherd66b94b2009-05-20 05:08:26 -0300733 fc->dev_type = FC_UNK;
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300734 err("no frontend driver found for this B2C2/FlexCop adapter");
735 return -ENODEV;
736
737fe_found:
738 info("found '%s' .", fc->fe->ops.info.name);
739 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
740 err("frontend registration failed!");
Trent Piephoeccd15a2009-06-11 05:33:00 -0300741 dvb_frontend_detach(fc->fe);
Patrick Boettcher6394cf52008-03-29 20:49:57 -0300742 fc->fe = NULL;
743 return -EINVAL;
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700744 }
745 fc->init_state |= FC_STATE_FE_INIT;
746 return 0;
747}
748
749void flexcop_frontend_exit(struct flexcop_device *fc)
750{
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300751 if (fc->init_state & FC_STATE_FE_INIT) {
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700752 dvb_unregister_frontend(fc->fe);
Andrew de Quinceyf52a8382006-08-08 09:10:09 -0300753 dvb_frontend_detach(fc->fe);
Andrew de Quincey2bfe0312006-08-08 09:10:08 -0300754 }
Johannes Stezenbach2add87a2005-05-16 21:54:10 -0700755 fc->init_state &= ~FC_STATE_FE_INIT;
756}