2 Samsung S5H1409 VSB/QAM demodulator driver
4 Copyright (C) 2006 Steven Toth <stoth@linuxtv.org>
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.
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.
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.
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 <media/dvb_frontend.h>
31 struct s5h1409_state
{
33 struct i2c_adapter
*i2c
;
35 /* configuration settings */
36 const struct s5h1409_config
*config
;
38 struct dvb_frontend frontend
;
40 /* previous uncorrected block counter */
41 enum fe_modulation current_modulation
;
43 u32 current_frequency
;
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
59 module_param(debug
, int, 0644);
60 MODULE_PARM_DESC(debug
, "Enable verbose debug messages");
62 #define dprintk if (debug) printk
64 /* Register values to initialise the demod, this will set VSB by default */
65 static struct init_tab
{
116 /* VSB SNR lookup table */
117 static struct vsb_snr_tab
{
163 /* QAM64 SNR lookup table */
164 static struct qam64_snr_tab
{
167 } qam64_snr_tab
[] = {
235 /* QAM256 SNR lookup table */
236 static struct qam256_snr_tab
{
239 } qam256_snr_tab
[] = {
312 /* 8 bit registers, 16 bit values */
313 static int s5h1409_writereg(struct s5h1409_state
*state
, u8 reg
, u16 data
)
316 u8 buf
[] = { reg
, data
>> 8, data
& 0xff };
318 struct i2c_msg msg
= { .addr
= state
->config
->demod_address
,
319 .flags
= 0, .buf
= buf
, .len
= 3 };
321 ret
= i2c_transfer(state
->i2c
, &msg
, 1);
324 printk(KERN_ERR
"%s: error (reg == 0x%02x, val == 0x%04x, ret == %i)\n",
325 __func__
, reg
, data
, ret
);
327 return (ret
!= 1) ? -1 : 0;
330 static u16
s5h1409_readreg(struct s5h1409_state
*state
, u8 reg
)
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 } };
342 ret
= i2c_transfer(state
->i2c
, msg
, 2);
345 printk("%s: readreg error (ret == %i)\n", __func__
, ret
);
346 return (b1
[0] << 8) | b1
[1];
349 static int s5h1409_softreset(struct dvb_frontend
*fe
)
351 struct s5h1409_state
*state
= fe
->demodulator_priv
;
353 dprintk("%s()\n", __func__
);
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
;
362 #define S5H1409_VSB_IF_FREQ 5380
363 #define S5H1409_QAM_IF_FREQ (state->config->qam_if)
365 static int s5h1409_set_if_freq(struct dvb_frontend
*fe
, int KHz
)
367 struct s5h1409_state
*state
= fe
->demodulator_priv
;
369 dprintk("%s(%d KHz)\n", __func__
, KHz
);
373 s5h1409_writereg(state
, 0x87, 0x014b);
374 s5h1409_writereg(state
, 0x88, 0x0cb5);
375 s5h1409_writereg(state
, 0x89, 0x03e2);
380 s5h1409_writereg(state
, 0x87, 0x01be);
381 s5h1409_writereg(state
, 0x88, 0x0436);
382 s5h1409_writereg(state
, 0x89, 0x054d);
385 state
->if_freq
= KHz
;
390 static int s5h1409_set_spectralinversion(struct dvb_frontend
*fe
, int inverted
)
392 struct s5h1409_state
*state
= fe
->demodulator_priv
;
394 dprintk("%s(%d)\n", __func__
, inverted
);
397 return s5h1409_writereg(state
, 0x1b, 0x1101); /* Inverted */
399 return s5h1409_writereg(state
, 0x1b, 0x0110); /* Normal */
402 static int s5h1409_enable_modulation(struct dvb_frontend
*fe
,
403 enum fe_modulation m
)
405 struct s5h1409_state
*state
= fe
->demodulator_priv
;
407 dprintk("%s(0x%08x)\n", __func__
, m
);
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);
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);
426 dprintk("%s() Invalid modulation\n", __func__
);
430 state
->current_modulation
= m
;
431 s5h1409_softreset(fe
);
436 static int s5h1409_i2c_gate_ctrl(struct dvb_frontend
*fe
, int enable
)
438 struct s5h1409_state
*state
= fe
->demodulator_priv
;
440 dprintk("%s(%d)\n", __func__
, enable
);
443 return s5h1409_writereg(state
, 0xf3, 1);
445 return s5h1409_writereg(state
, 0xf3, 0);
448 static int s5h1409_set_gpio(struct dvb_frontend
*fe
, int enable
)
450 struct s5h1409_state
*state
= fe
->demodulator_priv
;
452 dprintk("%s(%d)\n", __func__
, enable
);
455 return s5h1409_writereg(state
, 0xe3,
456 s5h1409_readreg(state
, 0xe3) | 0x1100);
458 return s5h1409_writereg(state
, 0xe3,
459 s5h1409_readreg(state
, 0xe3) & 0xfeff);
462 static int s5h1409_sleep(struct dvb_frontend
*fe
, int enable
)
464 struct s5h1409_state
*state
= fe
->demodulator_priv
;
466 dprintk("%s(%d)\n", __func__
, enable
);
468 return s5h1409_writereg(state
, 0xf2, enable
);
471 static int s5h1409_register_reset(struct dvb_frontend
*fe
)
473 struct s5h1409_state
*state
= fe
->demodulator_priv
;
475 dprintk("%s()\n", __func__
);
477 return s5h1409_writereg(state
, 0xfa, 0);
480 static void s5h1409_set_qam_amhum_mode(struct dvb_frontend
*fe
)
482 struct s5h1409_state
*state
= fe
->demodulator_priv
;
485 if (state
->qam_state
< QAM_STATE_INTERLEAVE_SET
) {
486 /* We should not perform amhum optimization until
487 the interleave mode has been configured */
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 */
497 /* QAM EQ lock check */
498 reg
= s5h1409_readreg(state
, 0xf0);
500 if ((reg
>> 13) & 0x1) {
503 s5h1409_writereg(state
, 0x96, 0x000c);
505 if (state
->qam_state
< QAM_STATE_QAM_OPTIMIZED_L3
) {
506 dprintk("%s() setting QAM state to OPT_L3\n",
508 s5h1409_writereg(state
, 0x93, 0x3130);
509 s5h1409_writereg(state
, 0x9e, 0x2836);
510 state
->qam_state
= QAM_STATE_QAM_OPTIMIZED_L3
;
513 if (state
->qam_state
< QAM_STATE_QAM_OPTIMIZED_L2
) {
514 dprintk("%s() setting QAM state to OPT_L2\n",
516 s5h1409_writereg(state
, 0x93, 0x3332);
517 s5h1409_writereg(state
, 0x9e, 0x2c37);
518 state
->qam_state
= QAM_STATE_QAM_OPTIMIZED_L2
;
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);
528 state
->qam_state
= QAM_STATE_QAM_OPTIMIZED_L1
;
533 static void s5h1409_set_qam_amhum_mode_legacy(struct dvb_frontend
*fe
)
535 struct s5h1409_state
*state
= fe
->demodulator_priv
;
538 if (state
->is_qam_locked
)
541 /* QAM EQ lock check */
542 reg
= s5h1409_readreg(state
, 0xf0);
544 if ((reg
>> 13) & 0x1) {
546 state
->is_qam_locked
= 1;
549 s5h1409_writereg(state
, 0x96, 0x00c);
550 if ((reg
< 0x38) || (reg
> 0x68)) {
551 s5h1409_writereg(state
, 0x93, 0x3332);
552 s5h1409_writereg(state
, 0x9e, 0x2c37);
554 s5h1409_writereg(state
, 0x93, 0x3130);
555 s5h1409_writereg(state
, 0x9e, 0x2836);
559 s5h1409_writereg(state
, 0x96, 0x0008);
560 s5h1409_writereg(state
, 0x93, 0x3332);
561 s5h1409_writereg(state
, 0x9e, 0x2c37);
565 static void s5h1409_set_qam_interleave_mode(struct dvb_frontend
*fe
)
567 struct s5h1409_state
*state
= fe
->demodulator_priv
;
570 if (state
->qam_state
>= QAM_STATE_INTERLEAVE_SET
) {
571 /* We've done the optimization already */
575 reg
= s5h1409_readreg(state
, 0xf1);
578 if ((reg
>> 15) & 0x1) {
579 if (state
->qam_state
== QAM_STATE_UNTUNED
||
580 state
->qam_state
== QAM_STATE_TUNING_STARTED
) {
581 dprintk("%s() setting QAM state to INTERLEAVE_SET\n",
583 reg1
= s5h1409_readreg(state
, 0xb2);
584 reg2
= s5h1409_readreg(state
, 0xad);
586 s5h1409_writereg(state
, 0x96, 0x0020);
587 s5h1409_writereg(state
, 0xad,
588 (((reg1
& 0xf000) >> 4) | (reg2
& 0xf0ff)));
589 state
->qam_state
= QAM_STATE_INTERLEAVE_SET
;
592 if (state
->qam_state
== QAM_STATE_UNTUNED
) {
593 dprintk("%s() setting QAM state to TUNING_STARTED\n",
595 s5h1409_writereg(state
, 0x96, 0x08);
596 s5h1409_writereg(state
, 0xab,
597 s5h1409_readreg(state
, 0xab) | 0x1001);
598 state
->qam_state
= QAM_STATE_TUNING_STARTED
;
603 static void s5h1409_set_qam_interleave_mode_legacy(struct dvb_frontend
*fe
)
605 struct s5h1409_state
*state
= fe
->demodulator_priv
;
608 reg
= s5h1409_readreg(state
, 0xf1);
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);
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);
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);
633 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
634 static int s5h1409_set_frontend(struct dvb_frontend
*fe
)
636 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
637 struct s5h1409_state
*state
= fe
->demodulator_priv
;
639 dprintk("%s(frequency=%d)\n", __func__
, p
->frequency
);
641 s5h1409_softreset(fe
);
643 state
->current_frequency
= p
->frequency
;
645 s5h1409_enable_modulation(fe
, p
->modulation
);
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);
655 /* Issue a reset to the demod so it knows to resync against the
656 newly tuned frequency */
657 s5h1409_softreset(fe
);
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
);
668 s5h1409_set_qam_amhum_mode_legacy(fe
);
669 s5h1409_set_qam_interleave_mode_legacy(fe
);
676 static int s5h1409_set_mpeg_timing(struct dvb_frontend
*fe
, int mode
)
678 struct s5h1409_state
*state
= fe
->demodulator_priv
;
681 dprintk("%s(%d)\n", __func__
, mode
);
683 val
= s5h1409_readreg(state
, 0xac) & 0xcfff;
685 case S5H1409_MPEGTIMING_CONTINUOUS_INVERTING_CLOCK
:
688 case S5H1409_MPEGTIMING_CONTINUOUS_NONINVERTING_CLOCK
:
689 dprintk("%s(%d) Mode1 or Defaulting\n", __func__
, mode
);
692 case S5H1409_MPEGTIMING_NONCONTINUOUS_INVERTING_CLOCK
:
695 case S5H1409_MPEGTIMING_NONCONTINUOUS_NONINVERTING_CLOCK
:
702 /* Configure MPEG Signal Timing charactistics */
703 return s5h1409_writereg(state
, 0xac, val
);
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
)
712 struct s5h1409_state
*state
= fe
->demodulator_priv
;
713 dprintk("%s()\n", __func__
);
715 s5h1409_sleep(fe
, 0);
716 s5h1409_register_reset(fe
);
718 for (i
= 0; i
< ARRAY_SIZE(init_tab
); i
++)
719 s5h1409_writereg(state
, init_tab
[i
].reg
, init_tab
[i
].data
);
721 /* The datasheet says that after initialisation, VSB is default */
722 state
->current_modulation
= VSB_8
;
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
727 if (state
->config
->hvr1600_opt
== S5H1409_HVR1600_OPTIMIZE
) {
729 s5h1409_writereg(state
, 0x09, 0x0050);
731 /* Unknown but Windows driver does it... */
732 s5h1409_writereg(state
, 0x21, 0x0001);
733 s5h1409_writereg(state
, 0x50, 0x030e);
736 s5h1409_writereg(state
, 0x82, 0x0800);
739 if (state
->config
->output_mode
== S5H1409_SERIAL_OUTPUT
)
740 s5h1409_writereg(state
, 0xab,
741 s5h1409_readreg(state
, 0xab) | 0x100); /* Serial */
743 s5h1409_writereg(state
, 0xab,
744 s5h1409_readreg(state
, 0xab) & 0xfeff); /* Parallel */
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
);
752 /* Note: Leaving the I2C gate closed. */
753 s5h1409_i2c_gate_ctrl(fe
, 0);
758 static int s5h1409_read_status(struct dvb_frontend
*fe
, enum fe_status
*status
)
760 struct s5h1409_state
*state
= fe
->demodulator_priv
;
762 u32 tuner_status
= 0;
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
);
777 /* Get the demodulator status */
778 reg
= s5h1409_readreg(state
, 0xf1);
780 *status
|= FE_HAS_VITERBI
;
782 *status
|= FE_HAS_LOCK
| FE_HAS_SYNC
;
784 switch (state
->config
->status_mode
) {
785 case S5H1409_DEMODLOCKING
:
786 if (*status
& FE_HAS_VITERBI
)
787 *status
|= FE_HAS_CARRIER
| FE_HAS_SIGNAL
;
789 case S5H1409_TUNERLOCKING
:
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);
795 fe
->ops
.tuner_ops
.get_status(fe
, &tuner_status
);
797 if (fe
->ops
.i2c_gate_ctrl
)
798 fe
->ops
.i2c_gate_ctrl(fe
, 0);
801 *status
|= FE_HAS_CARRIER
| FE_HAS_SIGNAL
;
805 dprintk("%s() status 0x%08x\n", __func__
, *status
);
810 static int s5h1409_qam256_lookup_snr(struct dvb_frontend
*fe
, u16
*snr
, u16 v
)
812 int i
, ret
= -EINVAL
;
813 dprintk("%s()\n", __func__
);
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
;
825 static int s5h1409_qam64_lookup_snr(struct dvb_frontend
*fe
, u16
*snr
, u16 v
)
827 int i
, ret
= -EINVAL
;
828 dprintk("%s()\n", __func__
);
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
;
840 static int s5h1409_vsb_lookup_snr(struct dvb_frontend
*fe
, u16
*snr
, u16 v
)
842 int i
, ret
= -EINVAL
;
843 dprintk("%s()\n", __func__
);
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
;
852 dprintk("%s() snr=%d\n", __func__
, *snr
);
856 static int s5h1409_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
858 struct s5h1409_state
*state
= fe
->demodulator_priv
;
860 dprintk("%s()\n", __func__
);
862 switch (state
->current_modulation
) {
864 reg
= s5h1409_readreg(state
, 0xf0) & 0xff;
865 return s5h1409_qam64_lookup_snr(fe
, snr
, reg
);
867 reg
= s5h1409_readreg(state
, 0xf0) & 0xff;
868 return s5h1409_qam256_lookup_snr(fe
, snr
, reg
);
870 reg
= s5h1409_readreg(state
, 0xf1) & 0x3ff;
871 return s5h1409_vsb_lookup_snr(fe
, snr
, reg
);
879 static int s5h1409_read_signal_strength(struct dvb_frontend
*fe
,
880 u16
*signal_strength
)
882 /* borrowed from lgdt330x.c
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%
891 int ret
= s5h1409_read_snr(fe
, &snr
);
893 *signal_strength
= 0;
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 */
900 /* Convert from SNR in dB * 10 to 8.24 fixed-point */
901 tmp
= (snr
* ((1 << 24) / 10));
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;
908 *signal_strength
= tmp
/ 8960;
914 static int s5h1409_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
916 struct s5h1409_state
*state
= fe
->demodulator_priv
;
918 *ucblocks
= s5h1409_readreg(state
, 0xb5);
923 static int s5h1409_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
925 return s5h1409_read_ucblocks(fe
, ber
);
928 static int s5h1409_get_frontend(struct dvb_frontend
*fe
,
929 struct dtv_frontend_properties
*p
)
931 struct s5h1409_state
*state
= fe
->demodulator_priv
;
933 p
->frequency
= state
->current_frequency
;
934 p
->modulation
= state
->current_modulation
;
939 static int s5h1409_get_tune_settings(struct dvb_frontend
*fe
,
940 struct dvb_frontend_tune_settings
*tune
)
942 tune
->min_delay_ms
= 1000;
946 static void s5h1409_release(struct dvb_frontend
*fe
)
948 struct s5h1409_state
*state
= fe
->demodulator_priv
;
952 static const struct dvb_frontend_ops s5h1409_ops
;
954 struct dvb_frontend
*s5h1409_attach(const struct s5h1409_config
*config
,
955 struct i2c_adapter
*i2c
)
957 struct s5h1409_state
*state
= NULL
;
960 /* allocate memory for the internal state */
961 state
= kzalloc(sizeof(struct s5h1409_state
), GFP_KERNEL
);
965 /* setup the state */
966 state
->config
= config
;
968 state
->current_modulation
= 0;
969 state
->if_freq
= S5H1409_VSB_IF_FREQ
;
971 /* check if the demod exists */
972 reg
= s5h1409_readreg(state
, 0x04);
973 if ((reg
!= 0x0066) && (reg
!= 0x007f))
976 /* create dvb_frontend */
977 memcpy(&state
->frontend
.ops
, &s5h1409_ops
,
978 sizeof(struct dvb_frontend_ops
));
979 state
->frontend
.demodulator_priv
= state
;
981 if (s5h1409_init(&state
->frontend
) != 0) {
982 printk(KERN_ERR
"%s: Failed to initialize correctly\n",
987 /* Note: Leaving the I2C gate open here. */
988 s5h1409_i2c_gate_ctrl(&state
->frontend
, 1);
990 return &state
->frontend
;
996 EXPORT_SYMBOL(s5h1409_attach
);
998 static const struct dvb_frontend_ops s5h1409_ops
= {
999 .delsys
= { SYS_ATSC
, SYS_DVBC_ANNEX_B
},
1001 .name
= "Samsung S5H1409 QAM/8VSB Frontend",
1002 .frequency_min_hz
= 54 * MHz
,
1003 .frequency_max_hz
= 858 * MHz
,
1004 .frequency_stepsize_hz
= 62500,
1005 .caps
= FE_CAN_QAM_64
| FE_CAN_QAM_256
| FE_CAN_8VSB
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
,
1021 MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
1022 MODULE_AUTHOR("Steven Toth");
1023 MODULE_LICENSE("GPL");