This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / drivers / media / dvb / b2c2 / flexcop-fe-tuner.c
1 /*
2  * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
3  *
4  * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
5  *
6  * see flexcop.c for copyright information.
7  */
8 #include "flexcop.h"
9
10 #include "stv0299.h"
11 #include "mt352.h"
12 #include "nxt2002.h"
13 #include "stv0297.h"
14 #include "mt312.h"
15
16 /* lnb control */
17
18 static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
19 {
20         struct flexcop_device *fc = fe->dvb->priv;
21         flexcop_ibi_value v;
22         deb_tuner("polarity/voltage = %u\n", voltage);
23
24         v = fc->read_ibi_reg(fc, misc_204);
25         switch (voltage) {
26                 case SEC_VOLTAGE_OFF:
27                         v.misc_204.ACPI1_sig = 1;
28                         break;
29                 case SEC_VOLTAGE_13:
30                         v.misc_204.ACPI1_sig = 0;
31                         v.misc_204.LNB_L_H_sig = 0;
32                         break;
33                 case SEC_VOLTAGE_18:
34                         v.misc_204.ACPI1_sig = 0;
35                         v.misc_204.LNB_L_H_sig = 1;
36                         break;
37                 default:
38                         err("unknown SEC_VOLTAGE value");
39                         return -EINVAL;
40         }
41         return fc->write_ibi_reg(fc, misc_204, v);
42 }
43
44 static int flexcop_sleep(struct dvb_frontend* fe)
45 {
46         struct flexcop_device *fc = fe->dvb->priv;
47 /*      flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
48
49         if (fc->fe_sleep)
50                 return fc->fe_sleep(fe);
51
52 /*      v.misc_204.ACPI3_sig = 1;
53         fc->write_ibi_reg(fc,misc_204,v);*/
54
55         return 0;
56 }
57
58 static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
59 {
60         /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
61         struct flexcop_device *fc = fe->dvb->priv;
62         flexcop_ibi_value v;
63         u16 ax;
64         v.raw = 0;
65
66         deb_tuner("tone = %u\n",tone);
67
68         switch (tone) {
69                 case SEC_TONE_ON:
70                         ax = 0x01ff;
71                         break;
72                 case SEC_TONE_OFF:
73                         ax = 0;
74                         break;
75                 default:
76                         err("unknown SEC_TONE value");
77                         return -EINVAL;
78         }
79
80         v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
81
82         v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
83         v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
84
85         return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
86 }
87
88 static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
89 {
90         flexcop_set_tone(fe, SEC_TONE_ON);
91         udelay(data ? 500 : 1000);
92         flexcop_set_tone(fe, SEC_TONE_OFF);
93         udelay(data ? 1000 : 500);
94 }
95
96 static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
97 {
98         int i, par = 1, d;
99
100         for (i = 7; i >= 0; i--) {
101                 d = (data >> i) & 1;
102                 par ^= d;
103                 flexcop_diseqc_send_bit(fe, d);
104         }
105
106         flexcop_diseqc_send_bit(fe, par);
107 }
108
109 static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
110 {
111         int i;
112
113         flexcop_set_tone(fe, SEC_TONE_OFF);
114         mdelay(16);
115
116         for (i = 0; i < len; i++)
117                 flexcop_diseqc_send_byte(fe,msg[i]);
118
119         mdelay(16);
120
121         if (burst != -1) {
122                 if (burst)
123                         flexcop_diseqc_send_byte(fe, 0xff);
124                 else {
125                         flexcop_set_tone(fe, SEC_TONE_ON);
126                         udelay(12500);
127                         flexcop_set_tone(fe, SEC_TONE_OFF);
128                 }
129                 msleep(20);
130         }
131         return 0;
132 }
133
134 static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
135 {
136         return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
137 }
138
139 static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
140 {
141         return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
142 }
143
144 /* dvb-s stv0299 */
145 static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
146 {
147         u8 aclk = 0;
148         u8 bclk = 0;
149
150         if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
151         else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
152         else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
153         else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
154         else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
155         else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
156
157         stv0299_writereg (fe, 0x13, aclk);
158         stv0299_writereg (fe, 0x14, bclk);
159         stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
160         stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
161         stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
162
163         return 0;
164 }
165
166 static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
167 {
168         u8 buf[4];
169         u32 div;
170         struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
171         struct flexcop_device *fc = fe->dvb->priv;
172
173         div = params->frequency / 125;
174
175         buf[0] = (div >> 8) & 0x7f;
176         buf[1] = div & 0xff;
177         buf[2] = 0x84;  /* 0xC4 */
178         buf[3] = 0x08;
179
180         if (params->frequency < 1500000) buf[3] |= 0x10;
181
182         if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
183                 return -EIO;
184         return 0;
185 }
186
187 static u8 samsung_tbmu24112_inittab[] = {
188              0x01, 0x15,
189              0x02, 0x30,
190              0x03, 0x00,
191              0x04, 0x7D,
192              0x05, 0x35,
193              0x06, 0x02,
194              0x07, 0x00,
195              0x08, 0xC3,
196              0x0C, 0x00,
197              0x0D, 0x81,
198              0x0E, 0x23,
199              0x0F, 0x12,
200              0x10, 0x7E,
201              0x11, 0x84,
202              0x12, 0xB9,
203              0x13, 0x88,
204              0x14, 0x89,
205              0x15, 0xC9,
206              0x16, 0x00,
207              0x17, 0x5C,
208              0x18, 0x00,
209              0x19, 0x00,
210              0x1A, 0x00,
211              0x1C, 0x00,
212              0x1D, 0x00,
213              0x1E, 0x00,
214              0x1F, 0x3A,
215              0x20, 0x2E,
216              0x21, 0x80,
217              0x22, 0xFF,
218              0x23, 0xC1,
219              0x28, 0x00,
220              0x29, 0x1E,
221              0x2A, 0x14,
222              0x2B, 0x0F,
223              0x2C, 0x09,
224              0x2D, 0x05,
225              0x31, 0x1F,
226              0x32, 0x19,
227              0x33, 0xFE,
228              0x34, 0x93,
229              0xff, 0xff,
230 };
231
232 static struct stv0299_config samsung_tbmu24112_config = {
233         .demod_address = 0x68,
234         .inittab = samsung_tbmu24112_inittab,
235         .mclk = 88000000UL,
236         .invert = 0,
237         .enhanced_tuning = 0,
238         .skip_reinit = 0,
239         .lock_output = STV0229_LOCKOUTPUT_LK,
240         .volt13_op0_op1 = STV0299_VOLT13_OP1,
241         .min_delay_ms = 100,
242         .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
243         .pll_set = samsung_tbmu24112_pll_set,
244 };
245
246 /* dvb-t mt352 */
247 static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
248 {
249         static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
250         static u8 mt352_reset [] = { 0x50, 0x80 };
251         static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
252         static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
253         static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
254
255         mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
256         udelay(2000);
257         mt352_write(fe, mt352_reset, sizeof(mt352_reset));
258         mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
259
260         mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
261         mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
262
263         return 0;
264 }
265
266 static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf)
267 {
268         u32 div;
269         unsigned char bs = 0;
270
271         #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
272         div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
273
274         if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
275         if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
276         if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
277
278         pllbuf[0] = 0xc2; /* Note: non-linux standard PLL i2c address */
279         pllbuf[1] = div >> 8;
280         pllbuf[2] = div & 0xff;
281         pllbuf[3] = 0xcc;
282         pllbuf[4] = bs;
283
284         return 0;
285 }
286
287 static struct mt352_config samsung_tdtc9251dh0_config = {
288
289         .demod_address = 0x0f,
290         .demod_init = samsung_tdtc9251dh0_demod_init,
291         .pll_set = samsung_tdtc9251dh0_pll_set,
292 };
293
294 static int nxt2002_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
295 {
296         struct flexcop_device *fc = fe->dvb->priv;
297         return request_firmware(fw, name, fc->dev);
298 }
299
300 static struct nxt2002_config samsung_tbmv_config = {
301         .demod_address = 0x0a,
302         .request_firmware = nxt2002_request_firmware,
303 };
304
305 static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
306 {
307         u8 buf[4];
308         u32 div;
309         struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
310         struct flexcop_device *fc = fe->dvb->priv;
311
312         div = (params->frequency + (125/2)) / 125;
313
314         buf[0] = (div >> 8) & 0x7f;
315         buf[1] = (div >> 0) & 0xff;
316         buf[2] = 0x84 | ((div >> 10) & 0x60);
317         buf[3] = 0x80;
318
319         if (params->frequency < 1550000)
320                 buf[3] |= 0x02;
321
322         if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
323                 return -EIO;
324         return 0;
325 }
326
327 static struct mt312_config skystar23_samsung_tbdu18132_config = {
328
329         .demod_address = 0x0e,
330         .pll_set = skystar23_samsung_tbdu18132_pll_set,
331 };
332
333 static struct stv0297_config alps_tdee4_stv0297_config = {
334         .demod_address = 0x1c,
335 //      .invert = 1,
336 //      .pll_set = alps_tdee4_stv0297_pll_set,
337 };
338
339 /* try to figure out the frontend, each card/box can have on of the following list */
340 int flexcop_frontend_init(struct flexcop_device *fc)
341 {
342         /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
343         if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
344                 fc->fe->ops->set_voltage = flexcop_set_voltage;
345
346                 fc->fe_sleep             = fc->fe->ops->sleep;
347                 fc->fe->ops->sleep       = flexcop_sleep;
348
349                 fc->dev_type          = FC_SKY;
350                 info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
351         } else
352         /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
353         if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
354                 fc->dev_type          = FC_AIR_DVB;
355                 info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
356         } else
357         /* try the air atsc (nxt2002) */
358         if ((fc->fe = nxt2002_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
359                 fc->dev_type          = FC_AIR_ATSC;
360                 info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
361         } else
362         /* try the cable dvb (stv0297) */
363         if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap, 0xf8)) != NULL) {
364                 fc->dev_type                        = FC_CABLE;
365                 info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
366         } else
367         /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
368         if ((fc->fe = vp310_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
369                 fc->fe->ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
370                 fc->fe->ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
371                 fc->fe->ops->set_tone               = flexcop_set_tone;
372                 fc->fe->ops->set_voltage            = flexcop_set_voltage;
373
374                 fc->fe_sleep                        = fc->fe->ops->sleep;
375                 fc->fe->ops->sleep                  = flexcop_sleep;
376
377                 fc->dev_type                        = FC_SKY_OLD;
378                 info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
379         }
380
381         if (fc->fe == NULL) {
382                 err("no frontend driver found for this B2C2/FlexCop adapter");
383                 return -ENODEV;
384         } else {
385                 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
386                         err("frontend registration failed!");
387                         if (fc->fe->ops->release != NULL)
388                                 fc->fe->ops->release(fc->fe);
389                         fc->fe = NULL;
390                         return -EINVAL;
391                 }
392         }
393         fc->init_state |= FC_STATE_FE_INIT;
394         return 0;
395 }
396
397 void flexcop_frontend_exit(struct flexcop_device *fc)
398 {
399         if (fc->init_state & FC_STATE_FE_INIT)
400                 dvb_unregister_frontend(fc->fe);
401
402         fc->init_state &= ~FC_STATE_FE_INIT;
403 }