Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fc0013.c
Go to the documentation of this file.
1 /*
2  * Fitipower FC0013 tuner driver
3  *
4  * Copyright (C) 2012 Hans-Frieder Vogt <[email protected]>
5  * partially based on driver code from Fitipower
6  * Copyright (C) 2010 Fitipower Integrated Technology Inc
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21  *
22  */
23 
24 #include "fc0013.h"
25 #include "fc0013-priv.h"
26 
27 static int fc0013_writereg(struct fc0013_priv *priv, u8 reg, u8 val)
28 {
29  u8 buf[2] = {reg, val};
30  struct i2c_msg msg = {
31  .addr = priv->addr, .flags = 0, .buf = buf, .len = 2
32  };
33 
34  if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
35  err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
36  return -EREMOTEIO;
37  }
38  return 0;
39 }
40 
41 static int fc0013_readreg(struct fc0013_priv *priv, u8 reg, u8 *val)
42 {
43  struct i2c_msg msg[2] = {
44  { .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
45  { .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
46  };
47 
48  if (i2c_transfer(priv->i2c, msg, 2) != 2) {
49  err("I2C read reg failed, reg: %02x", reg);
50  return -EREMOTEIO;
51  }
52  return 0;
53 }
54 
55 static int fc0013_release(struct dvb_frontend *fe)
56 {
57  kfree(fe->tuner_priv);
58  fe->tuner_priv = NULL;
59  return 0;
60 }
61 
62 static int fc0013_init(struct dvb_frontend *fe)
63 {
64  struct fc0013_priv *priv = fe->tuner_priv;
65  int i, ret = 0;
66  unsigned char reg[] = {
67  0x00, /* reg. 0x00: dummy */
68  0x09, /* reg. 0x01 */
69  0x16, /* reg. 0x02 */
70  0x00, /* reg. 0x03 */
71  0x00, /* reg. 0x04 */
72  0x17, /* reg. 0x05 */
73  0x02, /* reg. 0x06 */
74  0x0a, /* reg. 0x07: CHECK */
75  0xff, /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
76  Loop Bw 1/8 */
77  0x6f, /* reg. 0x09: enable LoopThrough */
78  0xb8, /* reg. 0x0a: Disable LO Test Buffer */
79  0x82, /* reg. 0x0b: CHECK */
80  0xfc, /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */
81  0x01, /* reg. 0x0d: AGC Not Forcing & LNA Forcing, may need 0x02 */
82  0x00, /* reg. 0x0e */
83  0x00, /* reg. 0x0f */
84  0x00, /* reg. 0x10 */
85  0x00, /* reg. 0x11 */
86  0x00, /* reg. 0x12 */
87  0x00, /* reg. 0x13 */
88  0x50, /* reg. 0x14: DVB-t High Gain, UHF.
89  Middle Gain: 0x48, Low Gain: 0x40 */
90  0x01, /* reg. 0x15 */
91  };
92 
93  switch (priv->xtal_freq) {
94  case FC_XTAL_27_MHZ:
95  case FC_XTAL_28_8_MHZ:
96  reg[0x07] |= 0x20;
97  break;
98  case FC_XTAL_36_MHZ:
99  default:
100  break;
101  }
102 
103  if (priv->dual_master)
104  reg[0x0c] |= 0x02;
105 
106  if (fe->ops.i2c_gate_ctrl)
107  fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
108 
109  for (i = 1; i < sizeof(reg); i++) {
110  ret = fc0013_writereg(priv, i, reg[i]);
111  if (ret)
112  break;
113  }
114 
115  if (fe->ops.i2c_gate_ctrl)
116  fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
117 
118  if (ret)
119  err("fc0013_writereg failed: %d", ret);
120 
121  return ret;
122 }
123 
124 static int fc0013_sleep(struct dvb_frontend *fe)
125 {
126  /* nothing to do here */
127  return 0;
128 }
129 
130 int fc0013_rc_cal_add(struct dvb_frontend *fe, int rc_val)
131 {
132  struct fc0013_priv *priv = fe->tuner_priv;
133  int ret;
134  u8 rc_cal;
135  int val;
136 
137  if (fe->ops.i2c_gate_ctrl)
138  fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
139 
140  /* push rc_cal value, get rc_cal value */
141  ret = fc0013_writereg(priv, 0x10, 0x00);
142  if (ret)
143  goto error_out;
144 
145  /* get rc_cal value */
146  ret = fc0013_readreg(priv, 0x10, &rc_cal);
147  if (ret)
148  goto error_out;
149 
150  rc_cal &= 0x0f;
151 
152  val = (int)rc_cal + rc_val;
153 
154  /* forcing rc_cal */
155  ret = fc0013_writereg(priv, 0x0d, 0x11);
156  if (ret)
157  goto error_out;
158 
159  /* modify rc_cal value */
160  if (val > 15)
161  ret = fc0013_writereg(priv, 0x10, 0x0f);
162  else if (val < 0)
163  ret = fc0013_writereg(priv, 0x10, 0x00);
164  else
165  ret = fc0013_writereg(priv, 0x10, (u8)val);
166 
167 error_out:
168  if (fe->ops.i2c_gate_ctrl)
169  fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
170 
171  return ret;
172 }
174 
176 {
177  struct fc0013_priv *priv = fe->tuner_priv;
178  int ret;
179 
180  if (fe->ops.i2c_gate_ctrl)
181  fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
182 
183  ret = fc0013_writereg(priv, 0x0d, 0x01);
184  if (!ret)
185  ret = fc0013_writereg(priv, 0x10, 0x00);
186 
187  if (fe->ops.i2c_gate_ctrl)
188  fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
189 
190  return ret;
191 }
193 
194 static int fc0013_set_vhf_track(struct fc0013_priv *priv, u32 freq)
195 {
196  int ret;
197  u8 tmp;
198 
199  ret = fc0013_readreg(priv, 0x1d, &tmp);
200  if (ret)
201  goto error_out;
202  tmp &= 0xe3;
203  if (freq <= 177500) { /* VHF Track: 7 */
204  ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
205  } else if (freq <= 184500) { /* VHF Track: 6 */
206  ret = fc0013_writereg(priv, 0x1d, tmp | 0x18);
207  } else if (freq <= 191500) { /* VHF Track: 5 */
208  ret = fc0013_writereg(priv, 0x1d, tmp | 0x14);
209  } else if (freq <= 198500) { /* VHF Track: 4 */
210  ret = fc0013_writereg(priv, 0x1d, tmp | 0x10);
211  } else if (freq <= 205500) { /* VHF Track: 3 */
212  ret = fc0013_writereg(priv, 0x1d, tmp | 0x0c);
213  } else if (freq <= 219500) { /* VHF Track: 2 */
214  ret = fc0013_writereg(priv, 0x1d, tmp | 0x08);
215  } else if (freq < 300000) { /* VHF Track: 1 */
216  ret = fc0013_writereg(priv, 0x1d, tmp | 0x04);
217  } else { /* UHF and GPS */
218  ret = fc0013_writereg(priv, 0x1d, tmp | 0x1c);
219  }
220  if (ret)
221  goto error_out;
222 error_out:
223  return ret;
224 }
225 
226 static int fc0013_set_params(struct dvb_frontend *fe)
227 {
228  struct fc0013_priv *priv = fe->tuner_priv;
229  int i, ret = 0;
231  u32 freq = p->frequency / 1000;
232  u32 delsys = p->delivery_system;
233  unsigned char reg[7], am, pm, multi, tmp;
234  unsigned long f_vco;
235  unsigned short xtal_freq_khz_2, xin, xdiv;
236  int vco_select = false;
237 
238  if (fe->callback) {
239  ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
240  FC_FE_CALLBACK_VHF_ENABLE, (freq > 300000 ? 0 : 1));
241  if (ret)
242  goto exit;
243  }
244 
245  switch (priv->xtal_freq) {
246  case FC_XTAL_27_MHZ:
247  xtal_freq_khz_2 = 27000 / 2;
248  break;
249  case FC_XTAL_36_MHZ:
250  xtal_freq_khz_2 = 36000 / 2;
251  break;
252  case FC_XTAL_28_8_MHZ:
253  default:
254  xtal_freq_khz_2 = 28800 / 2;
255  break;
256  }
257 
258  if (fe->ops.i2c_gate_ctrl)
259  fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
260 
261  /* set VHF track */
262  ret = fc0013_set_vhf_track(priv, freq);
263  if (ret)
264  goto exit;
265 
266  if (freq < 300000) {
267  /* enable VHF filter */
268  ret = fc0013_readreg(priv, 0x07, &tmp);
269  if (ret)
270  goto exit;
271  ret = fc0013_writereg(priv, 0x07, tmp | 0x10);
272  if (ret)
273  goto exit;
274 
275  /* disable UHF & disable GPS */
276  ret = fc0013_readreg(priv, 0x14, &tmp);
277  if (ret)
278  goto exit;
279  ret = fc0013_writereg(priv, 0x14, tmp & 0x1f);
280  if (ret)
281  goto exit;
282  } else if (freq <= 862000) {
283  /* disable VHF filter */
284  ret = fc0013_readreg(priv, 0x07, &tmp);
285  if (ret)
286  goto exit;
287  ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
288  if (ret)
289  goto exit;
290 
291  /* enable UHF & disable GPS */
292  ret = fc0013_readreg(priv, 0x14, &tmp);
293  if (ret)
294  goto exit;
295  ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x40);
296  if (ret)
297  goto exit;
298  } else {
299  /* disable VHF filter */
300  ret = fc0013_readreg(priv, 0x07, &tmp);
301  if (ret)
302  goto exit;
303  ret = fc0013_writereg(priv, 0x07, tmp & 0xef);
304  if (ret)
305  goto exit;
306 
307  /* disable UHF & enable GPS */
308  ret = fc0013_readreg(priv, 0x14, &tmp);
309  if (ret)
310  goto exit;
311  ret = fc0013_writereg(priv, 0x14, (tmp & 0x1f) | 0x20);
312  if (ret)
313  goto exit;
314  }
315 
316  /* select frequency divider and the frequency of VCO */
317  if (freq < 37084) { /* freq * 96 < 3560000 */
318  multi = 96;
319  reg[5] = 0x82;
320  reg[6] = 0x00;
321  } else if (freq < 55625) { /* freq * 64 < 3560000 */
322  multi = 64;
323  reg[5] = 0x02;
324  reg[6] = 0x02;
325  } else if (freq < 74167) { /* freq * 48 < 3560000 */
326  multi = 48;
327  reg[5] = 0x42;
328  reg[6] = 0x00;
329  } else if (freq < 111250) { /* freq * 32 < 3560000 */
330  multi = 32;
331  reg[5] = 0x82;
332  reg[6] = 0x02;
333  } else if (freq < 148334) { /* freq * 24 < 3560000 */
334  multi = 24;
335  reg[5] = 0x22;
336  reg[6] = 0x00;
337  } else if (freq < 222500) { /* freq * 16 < 3560000 */
338  multi = 16;
339  reg[5] = 0x42;
340  reg[6] = 0x02;
341  } else if (freq < 296667) { /* freq * 12 < 3560000 */
342  multi = 12;
343  reg[5] = 0x12;
344  reg[6] = 0x00;
345  } else if (freq < 445000) { /* freq * 8 < 3560000 */
346  multi = 8;
347  reg[5] = 0x22;
348  reg[6] = 0x02;
349  } else if (freq < 593334) { /* freq * 6 < 3560000 */
350  multi = 6;
351  reg[5] = 0x0a;
352  reg[6] = 0x00;
353  } else if (freq < 950000) { /* freq * 4 < 3800000 */
354  multi = 4;
355  reg[5] = 0x12;
356  reg[6] = 0x02;
357  } else {
358  multi = 2;
359  reg[5] = 0x0a;
360  reg[6] = 0x02;
361  }
362 
363  f_vco = freq * multi;
364 
365  if (f_vco >= 3060000) {
366  reg[6] |= 0x08;
367  vco_select = true;
368  }
369 
370  if (freq >= 45000) {
371  /* From divided value (XDIV) determined the FA and FP value */
372  xdiv = (unsigned short)(f_vco / xtal_freq_khz_2);
373  if ((f_vco - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
374  xdiv++;
375 
376  pm = (unsigned char)(xdiv / 8);
377  am = (unsigned char)(xdiv - (8 * pm));
378 
379  if (am < 2) {
380  reg[1] = am + 8;
381  reg[2] = pm - 1;
382  } else {
383  reg[1] = am;
384  reg[2] = pm;
385  }
386  } else {
387  /* fix for frequency less than 45 MHz */
388  reg[1] = 0x06;
389  reg[2] = 0x11;
390  }
391 
392  /* fix clock out */
393  reg[6] |= 0x20;
394 
395  /* From VCO frequency determines the XIN ( fractional part of Delta
396  Sigma PLL) and divided value (XDIV) */
397  xin = (unsigned short)(f_vco - (f_vco / xtal_freq_khz_2) * xtal_freq_khz_2);
398  xin = (xin << 15) / xtal_freq_khz_2;
399  if (xin >= 16384)
400  xin += 32768;
401 
402  reg[3] = xin >> 8;
403  reg[4] = xin & 0xff;
404 
405  if (delsys == SYS_DVBT) {
406  reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
407  switch (p->bandwidth_hz) {
408  case 6000000:
409  reg[6] |= 0x80;
410  break;
411  case 7000000:
412  reg[6] |= 0x40;
413  break;
414  case 8000000:
415  default:
416  break;
417  }
418  } else {
419  err("%s: modulation type not supported!", __func__);
420  return -EINVAL;
421  }
422 
423  /* modified for Realtek demod */
424  reg[5] |= 0x07;
425 
426  for (i = 1; i <= 6; i++) {
427  ret = fc0013_writereg(priv, i, reg[i]);
428  if (ret)
429  goto exit;
430  }
431 
432  ret = fc0013_readreg(priv, 0x11, &tmp);
433  if (ret)
434  goto exit;
435  if (multi == 64)
436  ret = fc0013_writereg(priv, 0x11, tmp | 0x04);
437  else
438  ret = fc0013_writereg(priv, 0x11, tmp & 0xfb);
439  if (ret)
440  goto exit;
441 
442  /* VCO Calibration */
443  ret = fc0013_writereg(priv, 0x0e, 0x80);
444  if (!ret)
445  ret = fc0013_writereg(priv, 0x0e, 0x00);
446 
447  /* VCO Re-Calibration if needed */
448  if (!ret)
449  ret = fc0013_writereg(priv, 0x0e, 0x00);
450 
451  if (!ret) {
452  msleep(10);
453  ret = fc0013_readreg(priv, 0x0e, &tmp);
454  }
455  if (ret)
456  goto exit;
457 
458  /* vco selection */
459  tmp &= 0x3f;
460 
461  if (vco_select) {
462  if (tmp > 0x3c) {
463  reg[6] &= ~0x08;
464  ret = fc0013_writereg(priv, 0x06, reg[6]);
465  if (!ret)
466  ret = fc0013_writereg(priv, 0x0e, 0x80);
467  if (!ret)
468  ret = fc0013_writereg(priv, 0x0e, 0x00);
469  }
470  } else {
471  if (tmp < 0x02) {
472  reg[6] |= 0x08;
473  ret = fc0013_writereg(priv, 0x06, reg[6]);
474  if (!ret)
475  ret = fc0013_writereg(priv, 0x0e, 0x80);
476  if (!ret)
477  ret = fc0013_writereg(priv, 0x0e, 0x00);
478  }
479  }
480 
481  priv->frequency = p->frequency;
482  priv->bandwidth = p->bandwidth_hz;
483 
484 exit:
485  if (fe->ops.i2c_gate_ctrl)
486  fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
487  if (ret)
488  warn("%s: failed: %d", __func__, ret);
489  return ret;
490 }
491 
492 static int fc0013_get_frequency(struct dvb_frontend *fe, u32 *frequency)
493 {
494  struct fc0013_priv *priv = fe->tuner_priv;
495  *frequency = priv->frequency;
496  return 0;
497 }
498 
499 static int fc0013_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
500 {
501  /* always ? */
502  *frequency = 0;
503  return 0;
504 }
505 
506 static int fc0013_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
507 {
508  struct fc0013_priv *priv = fe->tuner_priv;
509  *bandwidth = priv->bandwidth;
510  return 0;
511 }
512 
513 #define INPUT_ADC_LEVEL -8
514 
515 static int fc0013_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
516 {
517  struct fc0013_priv *priv = fe->tuner_priv;
518  int ret;
519  unsigned char tmp;
520  int int_temp, lna_gain, int_lna, tot_agc_gain, power;
521  const int fc0013_lna_gain_table[] = {
522  /* low gain */
523  -63, -58, -99, -73,
524  -63, -65, -54, -60,
525  /* middle gain */
526  71, 70, 68, 67,
527  65, 63, 61, 58,
528  /* high gain */
529  197, 191, 188, 186,
530  184, 182, 181, 179,
531  };
532 
533  if (fe->ops.i2c_gate_ctrl)
534  fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
535 
536  ret = fc0013_writereg(priv, 0x13, 0x00);
537  if (ret)
538  goto err;
539 
540  ret = fc0013_readreg(priv, 0x13, &tmp);
541  if (ret)
542  goto err;
543  int_temp = tmp;
544 
545  ret = fc0013_readreg(priv, 0x14, &tmp);
546  if (ret)
547  goto err;
548  lna_gain = tmp & 0x1f;
549 
550  if (fe->ops.i2c_gate_ctrl)
551  fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
552 
553  if (lna_gain < ARRAY_SIZE(fc0013_lna_gain_table)) {
554  int_lna = fc0013_lna_gain_table[lna_gain];
555  tot_agc_gain = (abs((int_temp >> 5) - 7) - 2 +
556  (int_temp & 0x1f)) * 2;
557  power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
558 
559  if (power >= 45)
560  *strength = 255; /* 100% */
561  else if (power < -95)
562  *strength = 0;
563  else
564  *strength = (power + 95) * 255 / 140;
565 
566  *strength |= *strength << 8;
567  } else {
568  ret = -1;
569  }
570 
571  goto exit;
572 
573 err:
574  if (fe->ops.i2c_gate_ctrl)
575  fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
576 exit:
577  if (ret)
578  warn("%s: failed: %d", __func__, ret);
579  return ret;
580 }
581 
582 static const struct dvb_tuner_ops fc0013_tuner_ops = {
583  .info = {
584  .name = "Fitipower FC0013",
585 
586  .frequency_min = 37000000, /* estimate */
587  .frequency_max = 1680000000, /* CHECK */
588  .frequency_step = 0,
589  },
590 
591  .release = fc0013_release,
592 
593  .init = fc0013_init,
594  .sleep = fc0013_sleep,
595 
596  .set_params = fc0013_set_params,
597 
598  .get_frequency = fc0013_get_frequency,
599  .get_if_frequency = fc0013_get_if_frequency,
600  .get_bandwidth = fc0013_get_bandwidth,
601 
602  .get_rf_strength = fc0013_get_rf_strength,
603 };
604 
606  struct i2c_adapter *i2c, u8 i2c_address, int dual_master,
607  enum fc001x_xtal_freq xtal_freq)
608 {
609  struct fc0013_priv *priv = NULL;
610 
611  priv = kzalloc(sizeof(struct fc0013_priv), GFP_KERNEL);
612  if (priv == NULL)
613  return NULL;
614 
615  priv->i2c = i2c;
616  priv->dual_master = dual_master;
617  priv->addr = i2c_address;
618  priv->xtal_freq = xtal_freq;
619 
620  info("Fitipower FC0013 successfully attached.");
621 
622  fe->tuner_priv = priv;
623 
624  memcpy(&fe->ops.tuner_ops, &fc0013_tuner_ops,
625  sizeof(struct dvb_tuner_ops));
626 
627  return fe;
628 }
630 
631 MODULE_DESCRIPTION("Fitipower FC0013 silicon tuner driver");
632 MODULE_AUTHOR("Hans-Frieder Vogt <[email protected]>");
633 MODULE_LICENSE("GPL");
634 MODULE_VERSION("0.2");