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