Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
s5h1409.c
Go to the documentation of this file.
1 /*
2  Samsung S5H1409 VSB/QAM demodulator driver
3 
4  Copyright (C) 2006 Steven Toth <[email protected]>
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 
20 */
21 
22 #include <linux/kernel.h>
23 #include <linux/init.h>
24 #include <linux/module.h>
25 #include <linux/string.h>
26 #include <linux/slab.h>
27 #include <linux/delay.h>
28 #include "dvb_frontend.h"
29 #include "s5h1409.h"
30 
31 struct s5h1409_state {
32 
33  struct i2c_adapter *i2c;
34 
35  /* configuration settings */
36  const struct s5h1409_config *config;
37 
39 
40  /* previous uncorrected block counter */
42 
44  int if_freq;
45 
47 
48  /* QAM tuning state goes through the following state transitions */
49 #define QAM_STATE_UNTUNED 0
50 #define QAM_STATE_TUNING_STARTED 1
51 #define QAM_STATE_INTERLEAVE_SET 2
52 #define QAM_STATE_QAM_OPTIMIZED_L1 3
53 #define QAM_STATE_QAM_OPTIMIZED_L2 4
54 #define QAM_STATE_QAM_OPTIMIZED_L3 5
56 };
57 
58 static int debug;
59 module_param(debug, int, 0644);
60 MODULE_PARM_DESC(debug, "Enable verbose debug messages");
61 
62 #define dprintk if (debug) printk
63 
64 /* Register values to initialise the demod, this will set VSB by default */
65 static struct init_tab {
66  u8 reg;
67  u16 data;
68 } init_tab[] = {
69  { 0x00, 0x0071, },
70  { 0x01, 0x3213, },
71  { 0x09, 0x0025, },
72  { 0x1c, 0x001d, },
73  { 0x1f, 0x002d, },
74  { 0x20, 0x001d, },
75  { 0x22, 0x0022, },
76  { 0x23, 0x0020, },
77  { 0x29, 0x110f, },
78  { 0x2a, 0x10b4, },
79  { 0x2b, 0x10ae, },
80  { 0x2c, 0x0031, },
81  { 0x31, 0x010d, },
82  { 0x32, 0x0100, },
83  { 0x44, 0x0510, },
84  { 0x54, 0x0104, },
85  { 0x58, 0x2222, },
86  { 0x59, 0x1162, },
87  { 0x5a, 0x3211, },
88  { 0x5d, 0x0370, },
89  { 0x5e, 0x0296, },
90  { 0x61, 0x0010, },
91  { 0x63, 0x4a00, },
92  { 0x65, 0x0800, },
93  { 0x71, 0x0003, },
94  { 0x72, 0x0470, },
95  { 0x81, 0x0002, },
96  { 0x82, 0x0600, },
97  { 0x86, 0x0002, },
98  { 0x8a, 0x2c38, },
99  { 0x8b, 0x2a37, },
100  { 0x92, 0x302f, },
101  { 0x93, 0x3332, },
102  { 0x96, 0x000c, },
103  { 0x99, 0x0101, },
104  { 0x9c, 0x2e37, },
105  { 0x9d, 0x2c37, },
106  { 0x9e, 0x2c37, },
107  { 0xab, 0x0100, },
108  { 0xac, 0x1003, },
109  { 0xad, 0x103f, },
110  { 0xe2, 0x0100, },
111  { 0xe3, 0x1000, },
112  { 0x28, 0x1010, },
113  { 0xb1, 0x000e, },
114 };
115 
116 /* VSB SNR lookup table */
117 static struct vsb_snr_tab {
118  u16 val;
119  u16 data;
120 } vsb_snr_tab[] = {
121  { 924, 300, },
122  { 923, 300, },
123  { 918, 295, },
124  { 915, 290, },
125  { 911, 285, },
126  { 906, 280, },
127  { 901, 275, },
128  { 896, 270, },
129  { 891, 265, },
130  { 885, 260, },
131  { 879, 255, },
132  { 873, 250, },
133  { 864, 245, },
134  { 858, 240, },
135  { 850, 235, },
136  { 841, 230, },
137  { 832, 225, },
138  { 823, 220, },
139  { 812, 215, },
140  { 802, 210, },
141  { 788, 205, },
142  { 778, 200, },
143  { 767, 195, },
144  { 753, 190, },
145  { 740, 185, },
146  { 725, 180, },
147  { 707, 175, },
148  { 689, 170, },
149  { 671, 165, },
150  { 656, 160, },
151  { 637, 155, },
152  { 616, 150, },
153  { 542, 145, },
154  { 519, 140, },
155  { 507, 135, },
156  { 497, 130, },
157  { 492, 125, },
158  { 474, 120, },
159  { 300, 111, },
160  { 0, 0, },
161 };
162 
163 /* QAM64 SNR lookup table */
164 static struct qam64_snr_tab {
165  u16 val;
166  u16 data;
167 } qam64_snr_tab[] = {
168  { 1, 0, },
169  { 12, 300, },
170  { 15, 290, },
171  { 18, 280, },
172  { 22, 270, },
173  { 23, 268, },
174  { 24, 266, },
175  { 25, 264, },
176  { 27, 262, },
177  { 28, 260, },
178  { 29, 258, },
179  { 30, 256, },
180  { 32, 254, },
181  { 33, 252, },
182  { 34, 250, },
183  { 35, 249, },
184  { 36, 248, },
185  { 37, 247, },
186  { 38, 246, },
187  { 39, 245, },
188  { 40, 244, },
189  { 41, 243, },
190  { 42, 241, },
191  { 43, 240, },
192  { 44, 239, },
193  { 45, 238, },
194  { 46, 237, },
195  { 47, 236, },
196  { 48, 235, },
197  { 49, 234, },
198  { 50, 233, },
199  { 51, 232, },
200  { 52, 231, },
201  { 53, 230, },
202  { 55, 229, },
203  { 56, 228, },
204  { 57, 227, },
205  { 58, 226, },
206  { 59, 225, },
207  { 60, 224, },
208  { 62, 223, },
209  { 63, 222, },
210  { 65, 221, },
211  { 66, 220, },
212  { 68, 219, },
213  { 69, 218, },
214  { 70, 217, },
215  { 72, 216, },
216  { 73, 215, },
217  { 75, 214, },
218  { 76, 213, },
219  { 78, 212, },
220  { 80, 211, },
221  { 81, 210, },
222  { 83, 209, },
223  { 84, 208, },
224  { 85, 207, },
225  { 87, 206, },
226  { 89, 205, },
227  { 91, 204, },
228  { 93, 203, },
229  { 95, 202, },
230  { 96, 201, },
231  { 104, 200, },
232  { 255, 0, },
233 };
234 
235 /* QAM256 SNR lookup table */
236 static struct qam256_snr_tab {
237  u16 val;
238  u16 data;
239 } qam256_snr_tab[] = {
240  { 1, 0, },
241  { 12, 400, },
242  { 13, 390, },
243  { 15, 380, },
244  { 17, 360, },
245  { 19, 350, },
246  { 22, 348, },
247  { 23, 346, },
248  { 24, 344, },
249  { 25, 342, },
250  { 26, 340, },
251  { 27, 336, },
252  { 28, 334, },
253  { 29, 332, },
254  { 30, 330, },
255  { 31, 328, },
256  { 32, 326, },
257  { 33, 325, },
258  { 34, 322, },
259  { 35, 320, },
260  { 37, 318, },
261  { 39, 316, },
262  { 40, 314, },
263  { 41, 312, },
264  { 42, 310, },
265  { 43, 308, },
266  { 46, 306, },
267  { 47, 304, },
268  { 49, 302, },
269  { 51, 300, },
270  { 53, 298, },
271  { 54, 297, },
272  { 55, 296, },
273  { 56, 295, },
274  { 57, 294, },
275  { 59, 293, },
276  { 60, 292, },
277  { 61, 291, },
278  { 63, 290, },
279  { 64, 289, },
280  { 65, 288, },
281  { 66, 287, },
282  { 68, 286, },
283  { 69, 285, },
284  { 71, 284, },
285  { 72, 283, },
286  { 74, 282, },
287  { 75, 281, },
288  { 76, 280, },
289  { 77, 279, },
290  { 78, 278, },
291  { 81, 277, },
292  { 83, 276, },
293  { 84, 275, },
294  { 86, 274, },
295  { 87, 273, },
296  { 89, 272, },
297  { 90, 271, },
298  { 92, 270, },
299  { 93, 269, },
300  { 95, 268, },
301  { 96, 267, },
302  { 98, 266, },
303  { 100, 265, },
304  { 102, 264, },
305  { 104, 263, },
306  { 105, 262, },
307  { 106, 261, },
308  { 110, 260, },
309  { 255, 0, },
310 };
311 
312 /* 8 bit registers, 16 bit values */
313 static int s5h1409_writereg(struct s5h1409_state *state, u8 reg, u16 data)
314 {
315  int ret;
316  u8 buf[] = { reg, data >> 8, data & 0xff };
317 
318  struct i2c_msg msg = { .addr = state->config->demod_address,
319  .flags = 0, .buf = buf, .len = 3 };
320 
321  ret = i2c_transfer(state->i2c, &msg, 1);
322 
323  if (ret != 1)
324  printk(KERN_ERR "%s: error (reg == 0x%02x, val == 0x%04x, "
325  "ret == %i)\n", __func__, reg, data, ret);
326 
327  return (ret != 1) ? -1 : 0;
328 }
329 
330 static u16 s5h1409_readreg(struct s5h1409_state *state, u8 reg)
331 {
332  int ret;
333  u8 b0[] = { reg };
334  u8 b1[] = { 0, 0 };
335 
336  struct i2c_msg msg[] = {
337  { .addr = state->config->demod_address, .flags = 0,
338  .buf = b0, .len = 1 },
339  { .addr = state->config->demod_address, .flags = I2C_M_RD,
340  .buf = b1, .len = 2 } };
341 
342  ret = i2c_transfer(state->i2c, msg, 2);
343 
344  if (ret != 2)
345  printk("%s: readreg error (ret == %i)\n", __func__, ret);
346  return (b1[0] << 8) | b1[1];
347 }
348 
349 static int s5h1409_softreset(struct dvb_frontend *fe)
350 {
351  struct s5h1409_state *state = fe->demodulator_priv;
352 
353  dprintk("%s()\n", __func__);
354 
355  s5h1409_writereg(state, 0xf5, 0);
356  s5h1409_writereg(state, 0xf5, 1);
357  state->is_qam_locked = 0;
358  state->qam_state = QAM_STATE_UNTUNED;
359  return 0;
360 }
361 
362 #define S5H1409_VSB_IF_FREQ 5380
363 #define S5H1409_QAM_IF_FREQ (state->config->qam_if)
364 
365 static int s5h1409_set_if_freq(struct dvb_frontend *fe, int KHz)
366 {
367  struct s5h1409_state *state = fe->demodulator_priv;
368 
369  dprintk("%s(%d KHz)\n", __func__, KHz);
370 
371  switch (KHz) {
372  case 4000:
373  s5h1409_writereg(state, 0x87, 0x014b);
374  s5h1409_writereg(state, 0x88, 0x0cb5);
375  s5h1409_writereg(state, 0x89, 0x03e2);
376  break;
377  case 5380:
378  case 44000:
379  default:
380  s5h1409_writereg(state, 0x87, 0x01be);
381  s5h1409_writereg(state, 0x88, 0x0436);
382  s5h1409_writereg(state, 0x89, 0x054d);
383  break;
384  }
385  state->if_freq = KHz;
386 
387  return 0;
388 }
389 
390 static int s5h1409_set_spectralinversion(struct dvb_frontend *fe, int inverted)
391 {
392  struct s5h1409_state *state = fe->demodulator_priv;
393 
394  dprintk("%s(%d)\n", __func__, inverted);
395 
396  if (inverted == 1)
397  return s5h1409_writereg(state, 0x1b, 0x1101); /* Inverted */
398  else
399  return s5h1409_writereg(state, 0x1b, 0x0110); /* Normal */
400 }
401 
402 static int s5h1409_enable_modulation(struct dvb_frontend *fe,
404 {
405  struct s5h1409_state *state = fe->demodulator_priv;
406 
407  dprintk("%s(0x%08x)\n", __func__, m);
408 
409  switch (m) {
410  case VSB_8:
411  dprintk("%s() VSB_8\n", __func__);
412  if (state->if_freq != S5H1409_VSB_IF_FREQ)
413  s5h1409_set_if_freq(fe, S5H1409_VSB_IF_FREQ);
414  s5h1409_writereg(state, 0xf4, 0);
415  break;
416  case QAM_64:
417  case QAM_256:
418  case QAM_AUTO:
419  dprintk("%s() QAM_AUTO (64/256)\n", __func__);
420  if (state->if_freq != S5H1409_QAM_IF_FREQ)
421  s5h1409_set_if_freq(fe, S5H1409_QAM_IF_FREQ);
422  s5h1409_writereg(state, 0xf4, 1);
423  s5h1409_writereg(state, 0x85, 0x110);
424  break;
425  default:
426  dprintk("%s() Invalid modulation\n", __func__);
427  return -EINVAL;
428  }
429 
430  state->current_modulation = m;
431  s5h1409_softreset(fe);
432 
433  return 0;
434 }
435 
436 static int s5h1409_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
437 {
438  struct s5h1409_state *state = fe->demodulator_priv;
439 
440  dprintk("%s(%d)\n", __func__, enable);
441 
442  if (enable)
443  return s5h1409_writereg(state, 0xf3, 1);
444  else
445  return s5h1409_writereg(state, 0xf3, 0);
446 }
447 
448 static int s5h1409_set_gpio(struct dvb_frontend *fe, int enable)
449 {
450  struct s5h1409_state *state = fe->demodulator_priv;
451 
452  dprintk("%s(%d)\n", __func__, enable);
453 
454  if (enable)
455  return s5h1409_writereg(state, 0xe3,
456  s5h1409_readreg(state, 0xe3) | 0x1100);
457  else
458  return s5h1409_writereg(state, 0xe3,
459  s5h1409_readreg(state, 0xe3) & 0xfeff);
460 }
461 
462 static int s5h1409_sleep(struct dvb_frontend *fe, int enable)
463 {
464  struct s5h1409_state *state = fe->demodulator_priv;
465 
466  dprintk("%s(%d)\n", __func__, enable);
467 
468  return s5h1409_writereg(state, 0xf2, enable);
469 }
470 
471 static int s5h1409_register_reset(struct dvb_frontend *fe)
472 {
473  struct s5h1409_state *state = fe->demodulator_priv;
474 
475  dprintk("%s()\n", __func__);
476 
477  return s5h1409_writereg(state, 0xfa, 0);
478 }
479 
480 static void s5h1409_set_qam_amhum_mode(struct dvb_frontend *fe)
481 {
482  struct s5h1409_state *state = fe->demodulator_priv;
483  u16 reg;
484 
485  if (state->qam_state < QAM_STATE_INTERLEAVE_SET) {
486  /* We should not perform amhum optimization until
487  the interleave mode has been configured */
488  return;
489  }
490 
491  if (state->qam_state == QAM_STATE_QAM_OPTIMIZED_L3) {
492  /* We've already reached the maximum optimization level, so
493  dont bother banging on the status registers */
494  return;
495  }
496 
497  /* QAM EQ lock check */
498  reg = s5h1409_readreg(state, 0xf0);
499 
500  if ((reg >> 13) & 0x1) {
501  reg &= 0xff;
502 
503  s5h1409_writereg(state, 0x96, 0x000c);
504  if (reg < 0x68) {
505  if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L3) {
506  dprintk("%s() setting QAM state to OPT_L3\n",
507  __func__);
508  s5h1409_writereg(state, 0x93, 0x3130);
509  s5h1409_writereg(state, 0x9e, 0x2836);
511  }
512  } else {
513  if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L2) {
514  dprintk("%s() setting QAM state to OPT_L2\n",
515  __func__);
516  s5h1409_writereg(state, 0x93, 0x3332);
517  s5h1409_writereg(state, 0x9e, 0x2c37);
519  }
520  }
521 
522  } else {
523  if (state->qam_state < QAM_STATE_QAM_OPTIMIZED_L1) {
524  dprintk("%s() setting QAM state to OPT_L1\n", __func__);
525  s5h1409_writereg(state, 0x96, 0x0008);
526  s5h1409_writereg(state, 0x93, 0x3332);
527  s5h1409_writereg(state, 0x9e, 0x2c37);
529  }
530  }
531 }
532 
533 static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend *fe)
534 {
535  struct s5h1409_state *state = fe->demodulator_priv;
536  u16 reg;
537 
538  if (state->is_qam_locked)
539  return;
540 
541  /* QAM EQ lock check */
542  reg = s5h1409_readreg(state, 0xf0);
543 
544  if ((reg >> 13) & 0x1) {
545 
546  state->is_qam_locked = 1;
547  reg &= 0xff;
548 
549  s5h1409_writereg(state, 0x96, 0x00c);
550  if ((reg < 0x38) || (reg > 0x68)) {
551  s5h1409_writereg(state, 0x93, 0x3332);
552  s5h1409_writereg(state, 0x9e, 0x2c37);
553  } else {
554  s5h1409_writereg(state, 0x93, 0x3130);
555  s5h1409_writereg(state, 0x9e, 0x2836);
556  }
557 
558  } else {
559  s5h1409_writereg(state, 0x96, 0x0008);
560  s5h1409_writereg(state, 0x93, 0x3332);
561  s5h1409_writereg(state, 0x9e, 0x2c37);
562  }
563 }
564 
565 static void s5h1409_set_qam_interleave_mode(struct dvb_frontend *fe)
566 {
567  struct s5h1409_state *state = fe->demodulator_priv;
568  u16 reg, reg1, reg2;
569 
570  if (state->qam_state >= QAM_STATE_INTERLEAVE_SET) {
571  /* We've done the optimization already */
572  return;
573  }
574 
575  reg = s5h1409_readreg(state, 0xf1);
576 
577  /* Master lock */
578  if ((reg >> 15) & 0x1) {
579  if (state->qam_state == QAM_STATE_UNTUNED ||
581  dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
582  __func__);
583  reg1 = s5h1409_readreg(state, 0xb2);
584  reg2 = s5h1409_readreg(state, 0xad);
585 
586  s5h1409_writereg(state, 0x96, 0x0020);
587  s5h1409_writereg(state, 0xad,
588  (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
590  }
591  } else {
592  if (state->qam_state == QAM_STATE_UNTUNED) {
593  dprintk("%s() setting QAM state to TUNING_STARTED\n",
594  __func__);
595  s5h1409_writereg(state, 0x96, 0x08);
596  s5h1409_writereg(state, 0xab,
597  s5h1409_readreg(state, 0xab) | 0x1001);
599  }
600  }
601 }
602 
603 static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend *fe)
604 {
605  struct s5h1409_state *state = fe->demodulator_priv;
606  u16 reg, reg1, reg2;
607 
608  reg = s5h1409_readreg(state, 0xf1);
609 
610  /* Master lock */
611  if ((reg >> 15) & 0x1) {
612  if (state->qam_state != 2) {
613  state->qam_state = 2;
614  reg1 = s5h1409_readreg(state, 0xb2);
615  reg2 = s5h1409_readreg(state, 0xad);
616 
617  s5h1409_writereg(state, 0x96, 0x20);
618  s5h1409_writereg(state, 0xad,
619  (((reg1 & 0xf000) >> 4) | (reg2 & 0xf0ff)));
620  s5h1409_writereg(state, 0xab,
621  s5h1409_readreg(state, 0xab) & 0xeffe);
622  }
623  } else {
624  if (state->qam_state != 1) {
625  state->qam_state = 1;
626  s5h1409_writereg(state, 0x96, 0x08);
627  s5h1409_writereg(state, 0xab,
628  s5h1409_readreg(state, 0xab) | 0x1001);
629  }
630  }
631 }
632 
633 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
634 static int s5h1409_set_frontend(struct dvb_frontend *fe)
635 {
637  struct s5h1409_state *state = fe->demodulator_priv;
638 
639  dprintk("%s(frequency=%d)\n", __func__, p->frequency);
640 
641  s5h1409_softreset(fe);
642 
643  state->current_frequency = p->frequency;
644 
645  s5h1409_enable_modulation(fe, p->modulation);
646 
647  if (fe->ops.tuner_ops.set_params) {
648  if (fe->ops.i2c_gate_ctrl)
649  fe->ops.i2c_gate_ctrl(fe, 1);
650  fe->ops.tuner_ops.set_params(fe);
651  if (fe->ops.i2c_gate_ctrl)
652  fe->ops.i2c_gate_ctrl(fe, 0);
653  }
654 
655  /* Issue a reset to the demod so it knows to resync against the
656  newly tuned frequency */
657  s5h1409_softreset(fe);
658 
659  /* Optimize the demod for QAM */
660  if (state->current_modulation != VSB_8) {
661  /* This almost certainly applies to all boards, but for now
662  only do it for the HVR-1600. Once the other boards are
663  tested, the "legacy" versions can just go away */
664  if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
665  s5h1409_set_qam_interleave_mode(fe);
666  s5h1409_set_qam_amhum_mode(fe);
667  } else {
668  s5h1409_set_qam_amhum_mode_legacy(fe);
669  s5h1409_set_qam_interleave_mode_legacy(fe);
670  }
671  }
672 
673  return 0;
674 }
675 
676 static int s5h1409_set_mpeg_timing(struct dvb_frontend *fe, int mode)
677 {
678  struct s5h1409_state *state = fe->demodulator_priv;
679  u16 val;
680 
681  dprintk("%s(%d)\n", __func__, mode);
682 
683  val = s5h1409_readreg(state, 0xac) & 0xcfff;
684  switch (mode) {
686  val |= 0x0000;
687  break;
689  dprintk("%s(%d) Mode1 or Defaulting\n", __func__, mode);
690  val |= 0x1000;
691  break;
693  val |= 0x2000;
694  break;
696  val |= 0x3000;
697  break;
698  default:
699  return -EINVAL;
700  }
701 
702  /* Configure MPEG Signal Timing charactistics */
703  return s5h1409_writereg(state, 0xac, val);
704 }
705 
706 /* Reset the demod hardware and reset all of the configuration registers
707  to a default state. */
708 static int s5h1409_init(struct dvb_frontend *fe)
709 {
710  int i;
711 
712  struct s5h1409_state *state = fe->demodulator_priv;
713  dprintk("%s()\n", __func__);
714 
715  s5h1409_sleep(fe, 0);
716  s5h1409_register_reset(fe);
717 
718  for (i = 0; i < ARRAY_SIZE(init_tab); i++)
719  s5h1409_writereg(state, init_tab[i].reg, init_tab[i].data);
720 
721  /* The datasheet says that after initialisation, VSB is default */
722  state->current_modulation = VSB_8;
723 
724  /* Optimize for the HVR-1600 if appropriate. Note that some of these
725  may get folded into the generic case after testing with other
726  devices */
727  if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
728  /* VSB AGC REF */
729  s5h1409_writereg(state, 0x09, 0x0050);
730 
731  /* Unknown but Windows driver does it... */
732  s5h1409_writereg(state, 0x21, 0x0001);
733  s5h1409_writereg(state, 0x50, 0x030e);
734 
735  /* QAM AGC REF */
736  s5h1409_writereg(state, 0x82, 0x0800);
737  }
738 
739  if (state->config->output_mode == S5H1409_SERIAL_OUTPUT)
740  s5h1409_writereg(state, 0xab,
741  s5h1409_readreg(state, 0xab) | 0x100); /* Serial */
742  else
743  s5h1409_writereg(state, 0xab,
744  s5h1409_readreg(state, 0xab) & 0xfeff); /* Parallel */
745 
746  s5h1409_set_spectralinversion(fe, state->config->inversion);
747  s5h1409_set_if_freq(fe, state->if_freq);
748  s5h1409_set_gpio(fe, state->config->gpio);
749  s5h1409_set_mpeg_timing(fe, state->config->mpeg_timing);
750  s5h1409_softreset(fe);
751 
752  /* Note: Leaving the I2C gate closed. */
753  s5h1409_i2c_gate_ctrl(fe, 0);
754 
755  return 0;
756 }
757 
758 static int s5h1409_read_status(struct dvb_frontend *fe, fe_status_t *status)
759 {
760  struct s5h1409_state *state = fe->demodulator_priv;
761  u16 reg;
762  u32 tuner_status = 0;
763 
764  *status = 0;
765 
766  /* Optimize the demod for QAM */
767  if (state->current_modulation != VSB_8) {
768  /* This almost certainly applies to all boards, but for now
769  only do it for the HVR-1600. Once the other boards are
770  tested, the "legacy" versions can just go away */
771  if (state->config->hvr1600_opt == S5H1409_HVR1600_OPTIMIZE) {
772  s5h1409_set_qam_interleave_mode(fe);
773  s5h1409_set_qam_amhum_mode(fe);
774  }
775  }
776 
777  /* Get the demodulator status */
778  reg = s5h1409_readreg(state, 0xf1);
779  if (reg & 0x1000)
780  *status |= FE_HAS_VITERBI;
781  if (reg & 0x8000)
782  *status |= FE_HAS_LOCK | FE_HAS_SYNC;
783 
784  switch (state->config->status_mode) {
786  if (*status & FE_HAS_VITERBI)
787  *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
788  break;
790  /* Get the tuner status */
791  if (fe->ops.tuner_ops.get_status) {
792  if (fe->ops.i2c_gate_ctrl)
793  fe->ops.i2c_gate_ctrl(fe, 1);
794 
795  fe->ops.tuner_ops.get_status(fe, &tuner_status);
796 
797  if (fe->ops.i2c_gate_ctrl)
798  fe->ops.i2c_gate_ctrl(fe, 0);
799  }
800  if (tuner_status)
801  *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
802  break;
803  }
804 
805  dprintk("%s() status 0x%08x\n", __func__, *status);
806 
807  return 0;
808 }
809 
810 static int s5h1409_qam256_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
811 {
812  int i, ret = -EINVAL;
813  dprintk("%s()\n", __func__);
814 
815  for (i = 0; i < ARRAY_SIZE(qam256_snr_tab); i++) {
816  if (v < qam256_snr_tab[i].val) {
817  *snr = qam256_snr_tab[i].data;
818  ret = 0;
819  break;
820  }
821  }
822  return ret;
823 }
824 
825 static int s5h1409_qam64_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
826 {
827  int i, ret = -EINVAL;
828  dprintk("%s()\n", __func__);
829 
830  for (i = 0; i < ARRAY_SIZE(qam64_snr_tab); i++) {
831  if (v < qam64_snr_tab[i].val) {
832  *snr = qam64_snr_tab[i].data;
833  ret = 0;
834  break;
835  }
836  }
837  return ret;
838 }
839 
840 static int s5h1409_vsb_lookup_snr(struct dvb_frontend *fe, u16 *snr, u16 v)
841 {
842  int i, ret = -EINVAL;
843  dprintk("%s()\n", __func__);
844 
845  for (i = 0; i < ARRAY_SIZE(vsb_snr_tab); i++) {
846  if (v > vsb_snr_tab[i].val) {
847  *snr = vsb_snr_tab[i].data;
848  ret = 0;
849  break;
850  }
851  }
852  dprintk("%s() snr=%d\n", __func__, *snr);
853  return ret;
854 }
855 
856 static int s5h1409_read_snr(struct dvb_frontend *fe, u16 *snr)
857 {
858  struct s5h1409_state *state = fe->demodulator_priv;
859  u16 reg;
860  dprintk("%s()\n", __func__);
861 
862  switch (state->current_modulation) {
863  case QAM_64:
864  reg = s5h1409_readreg(state, 0xf0) & 0xff;
865  return s5h1409_qam64_lookup_snr(fe, snr, reg);
866  case QAM_256:
867  reg = s5h1409_readreg(state, 0xf0) & 0xff;
868  return s5h1409_qam256_lookup_snr(fe, snr, reg);
869  case VSB_8:
870  reg = s5h1409_readreg(state, 0xf1) & 0x3ff;
871  return s5h1409_vsb_lookup_snr(fe, snr, reg);
872  default:
873  break;
874  }
875 
876  return -EINVAL;
877 }
878 
879 static int s5h1409_read_signal_strength(struct dvb_frontend *fe,
880  u16 *signal_strength)
881 {
882  /* borrowed from lgdt330x.c
883  *
884  * Calculate strength from SNR up to 35dB
885  * Even though the SNR can go higher than 35dB,
886  * there is some comfort factor in having a range of
887  * strong signals that can show at 100%
888  */
889  u16 snr;
890  u32 tmp;
891  int ret = s5h1409_read_snr(fe, &snr);
892 
893  *signal_strength = 0;
894 
895  if (0 == ret) {
896  /* The following calculation method was chosen
897  * purely for the sake of code re-use from the
898  * other demod drivers that use this method */
899 
900  /* Convert from SNR in dB * 10 to 8.24 fixed-point */
901  tmp = (snr * ((1 << 24) / 10));
902 
903  /* Convert from 8.24 fixed-point to
904  * scale the range 0 - 35*2^24 into 0 - 65535*/
905  if (tmp >= 8960 * 0x10000)
906  *signal_strength = 0xffff;
907  else
908  *signal_strength = tmp / 8960;
909  }
910 
911  return ret;
912 }
913 
914 static int s5h1409_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
915 {
916  struct s5h1409_state *state = fe->demodulator_priv;
917 
918  *ucblocks = s5h1409_readreg(state, 0xb5);
919 
920  return 0;
921 }
922 
923 static int s5h1409_read_ber(struct dvb_frontend *fe, u32 *ber)
924 {
925  return s5h1409_read_ucblocks(fe, ber);
926 }
927 
928 static int s5h1409_get_frontend(struct dvb_frontend *fe)
929 {
931  struct s5h1409_state *state = fe->demodulator_priv;
932 
933  p->frequency = state->current_frequency;
934  p->modulation = state->current_modulation;
935 
936  return 0;
937 }
938 
939 static int s5h1409_get_tune_settings(struct dvb_frontend *fe,
940  struct dvb_frontend_tune_settings *tune)
941 {
942  tune->min_delay_ms = 1000;
943  return 0;
944 }
945 
946 static void s5h1409_release(struct dvb_frontend *fe)
947 {
948  struct s5h1409_state *state = fe->demodulator_priv;
949  kfree(state);
950 }
951 
952 static struct dvb_frontend_ops s5h1409_ops;
953 
955  struct i2c_adapter *i2c)
956 {
957  struct s5h1409_state *state = NULL;
958  u16 reg;
959 
960  /* allocate memory for the internal state */
961  state = kzalloc(sizeof(struct s5h1409_state), GFP_KERNEL);
962  if (state == NULL)
963  goto error;
964 
965  /* setup the state */
966  state->config = config;
967  state->i2c = i2c;
968  state->current_modulation = 0;
969  state->if_freq = S5H1409_VSB_IF_FREQ;
970 
971  /* check if the demod exists */
972  reg = s5h1409_readreg(state, 0x04);
973  if ((reg != 0x0066) && (reg != 0x007f))
974  goto error;
975 
976  /* create dvb_frontend */
977  memcpy(&state->frontend.ops, &s5h1409_ops,
978  sizeof(struct dvb_frontend_ops));
979  state->frontend.demodulator_priv = state;
980 
981  if (s5h1409_init(&state->frontend) != 0) {
982  printk(KERN_ERR "%s: Failed to initialize correctly\n",
983  __func__);
984  goto error;
985  }
986 
987  /* Note: Leaving the I2C gate open here. */
988  s5h1409_i2c_gate_ctrl(&state->frontend, 1);
989 
990  return &state->frontend;
991 
992 error:
993  kfree(state);
994  return NULL;
995 }
997 
998 static struct dvb_frontend_ops s5h1409_ops = {
999  .delsys = { SYS_ATSC, SYS_DVBC_ANNEX_B },
1000  .info = {
1001  .name = "Samsung S5H1409 QAM/8VSB Frontend",
1002  .frequency_min = 54000000,
1003  .frequency_max = 858000000,
1004  .frequency_stepsize = 62500,
1006  },
1007 
1008  .init = s5h1409_init,
1009  .i2c_gate_ctrl = s5h1409_i2c_gate_ctrl,
1010  .set_frontend = s5h1409_set_frontend,
1011  .get_frontend = s5h1409_get_frontend,
1012  .get_tune_settings = s5h1409_get_tune_settings,
1013  .read_status = s5h1409_read_status,
1014  .read_ber = s5h1409_read_ber,
1015  .read_signal_strength = s5h1409_read_signal_strength,
1016  .read_snr = s5h1409_read_snr,
1017  .read_ucblocks = s5h1409_read_ucblocks,
1018  .release = s5h1409_release,
1019 };
1020 
1021 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
1022 MODULE_AUTHOR("Steven Toth");
1023 MODULE_LICENSE("GPL");
1024 
1025 
1026 /*
1027  * Local variables:
1028  * c-basic-offset: 8
1029  */