2 * Abilis Systems Single DVB-T Receiver
3 * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
4 * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
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, or (at your option)
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.
20 #include <linux/version.h>
22 #include "as102_drv.h"
23 #include "as10x_types.h"
24 #include "as10x_cmd.h"
26 extern int elna_enable
;
28 #if defined(CONFIG_DVB_CORE) || defined(CONFIG_DVB_CORE_MODULE)
29 static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters
*dst
,
30 struct as10x_tps
*src
);
32 static void as102_fe_copy_tune_parameters(struct as10x_tune_args
*dst
,
33 struct dvb_frontend_parameters
*src
);
35 static void as102_fe_release(struct dvb_frontend
*fe
)
37 struct as102_dev_t
*dev
;
41 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
45 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
46 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
49 /* send abilis command: TURN_OFF */
50 as10x_cmd_turn_off(&dev
->bus_adap
);
52 mutex_unlock(&dev
->bus_adap
.lock
);
55 /* release frontend callback ops */
56 memset(&fe
->ops
, 0, sizeof(struct dvb_frontend_ops
));
58 /* flush statistics */
59 memset(&dev
->demod_stats
, 0, sizeof(dev
->demod_stats
));
60 dev
->signal_strength
= 0;
63 /* reset tuner private data */
64 /* fe->tuner_priv = NULL; */
69 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
70 static int as102_fe_init(struct dvb_frontend
*fe
)
73 struct as102_dev_t
*dev
;
77 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
81 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
85 ret
= as10x_cmd_set_context(&dev
->bus_adap
, 1010, 0xC0);
87 /* send abilis command: TURN_ON */
88 ret
= as10x_cmd_turn_on(&dev
->bus_adap
);
90 mutex_unlock(&dev
->bus_adap
.lock
);
93 return (ret
< 0) ? -EINVAL
: 0;
97 static int as102_fe_set_frontend(struct dvb_frontend
*fe
,
98 struct dvb_frontend_parameters
*params
)
101 struct as102_dev_t
*dev
;
102 struct as10x_tune_args tune_args
= { 0 };
106 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
110 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
113 as102_fe_copy_tune_parameters(&tune_args
, params
);
115 /* send abilis command: SET_TUNE */
116 ret
= as10x_cmd_set_tune(&dev
->bus_adap
, &tune_args
);
118 dprintk(debug
, "as10x_cmd_set_tune failed. (err = %d)\n", ret
);
120 mutex_unlock(&dev
->bus_adap
.lock
);
123 return (ret
< 0) ? -EINVAL
: 0;
126 static int as102_fe_get_frontend(struct dvb_frontend
*fe
,
127 struct dvb_frontend_parameters
*p
) {
129 struct as102_dev_t
*dev
;
130 struct as10x_tps tps
= { 0 };
134 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
138 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
141 /* send abilis command: GET_TPS */
142 ret
= as10x_cmd_get_tps(&dev
->bus_adap
, &tps
);
145 as10x_fe_copy_tps_parameters(p
, &tps
);
147 mutex_unlock(&dev
->bus_adap
.lock
);
150 return (ret
< 0) ? -EINVAL
: 0;
153 static int as102_fe_get_tune_settings(struct dvb_frontend
*fe
,
154 struct dvb_frontend_tune_settings
*settings
) {
158 dprintk(debug
, "step_size = %d\n", settings
->step_size
);
159 dprintk(debug
, "max_drift = %d\n", settings
->max_drift
);
160 dprintk(debug
, "min_delay_ms = %d -> %d\n", settings
->min_delay_ms
,
164 settings
->min_delay_ms
= 1000;
171 static int as102_fe_read_status(struct dvb_frontend
*fe
, fe_status_t
*status
)
174 struct as102_dev_t
*dev
;
175 struct as10x_tune_status tstate
= { 0 };
179 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
183 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
186 /* send abilis command: GET_TUNE_STATUS */
187 ret
= as10x_cmd_get_tune_status(&dev
->bus_adap
, &tstate
);
189 dprintk(debug
, "as10x_cmd_get_tune_status failed (err = %d)\n",
194 dev
->signal_strength
= tstate
.signal_strength
;
195 dev
->ber
= tstate
.BER
;
197 switch (tstate
.tune_state
) {
198 case TUNE_STATUS_SIGNAL_DVB_OK
:
199 *status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
201 case TUNE_STATUS_STREAM_DETECTED
:
202 *status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_SYNC
;
204 case TUNE_STATUS_STREAM_TUNED
:
205 *status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_SYNC
|
209 *status
= TUNE_STATUS_NOT_TUNED
;
212 dprintk(debug
, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
213 tstate
.tune_state
, tstate
.signal_strength
,
214 tstate
.PER
, tstate
.BER
);
216 if (*status
& FE_HAS_LOCK
) {
217 if (as10x_cmd_get_demod_stats(&dev
->bus_adap
,
218 (struct as10x_demod_stats
*) &dev
->demod_stats
) < 0) {
219 memset(&dev
->demod_stats
, 0, sizeof(dev
->demod_stats
));
220 dprintk(debug
, "as10x_cmd_get_demod_stats failed "
221 "(probably not tuned)\n");
224 "demod status: fc: 0x%08x, bad fc: 0x%08x, "
225 "bytes corrected: 0x%08x , MER: 0x%04x\n",
226 dev
->demod_stats
.frame_count
,
227 dev
->demod_stats
.bad_frame_count
,
228 dev
->demod_stats
.bytes_fixed_by_rs
,
229 dev
->demod_stats
.mer
);
232 memset(&dev
->demod_stats
, 0, sizeof(dev
->demod_stats
));
236 mutex_unlock(&dev
->bus_adap
.lock
);
244 * - the SNR will be returned in linear terms, i.e. not in dB
245 * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB
246 * - the accuracy is >2dB for SNR values outside this range
248 static int as102_fe_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
250 struct as102_dev_t
*dev
;
254 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
258 *snr
= dev
->demod_stats
.mer
;
264 static int as102_fe_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
266 struct as102_dev_t
*dev
;
270 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
280 static int as102_fe_read_signal_strength(struct dvb_frontend
*fe
,
283 struct as102_dev_t
*dev
;
287 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
291 *strength
= (((0xffff * 400) * dev
->signal_strength
+ 41000) * 2);
297 static int as102_fe_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
299 struct as102_dev_t
*dev
;
303 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
307 if (dev
->demod_stats
.has_started
)
308 *ucblocks
= dev
->demod_stats
.bad_frame_count
;
316 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
317 static int as102_fe_ts_bus_ctrl(struct dvb_frontend
*fe
, int acquire
)
319 struct as102_dev_t
*dev
;
324 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
328 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
333 as10x_cmd_set_context(&dev
->bus_adap
, 1010, 0xC0);
335 ret
= as10x_cmd_turn_on(&dev
->bus_adap
);
337 ret
= as10x_cmd_turn_off(&dev
->bus_adap
);
340 mutex_unlock(&dev
->bus_adap
.lock
);
347 static struct dvb_frontend_ops as102_fe_ops
= {
349 .name
= "Unknown AS102 device",
351 .frequency_min
= 174000000,
352 .frequency_max
= 862000000,
353 .frequency_stepsize
= 166667,
354 .caps
= FE_CAN_INVERSION_AUTO
355 | FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
356 | FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
357 | FE_CAN_QAM_16
| FE_CAN_QAM_64
| FE_CAN_QPSK
359 | FE_CAN_TRANSMISSION_MODE_AUTO
360 | FE_CAN_GUARD_INTERVAL_AUTO
361 | FE_CAN_HIERARCHY_AUTO
366 .set_frontend
= as102_fe_set_frontend
,
367 .get_frontend
= as102_fe_get_frontend
,
368 .get_tune_settings
= as102_fe_get_tune_settings
,
371 .read_status
= as102_fe_read_status
,
372 .read_snr
= as102_fe_read_snr
,
373 .read_ber
= as102_fe_read_ber
,
374 .read_signal_strength
= as102_fe_read_signal_strength
,
375 .read_ucblocks
= as102_fe_read_ucblocks
,
377 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
378 .ts_bus_ctrl
= as102_fe_ts_bus_ctrl
,
380 .release
= as102_fe_release
,
381 .init
= as102_fe_init
,
385 int as102_dvb_unregister_fe(struct dvb_frontend
*fe
)
387 /* unregister frontend */
388 dvb_unregister_frontend(fe
);
390 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 19))
391 /* detach frontend */
392 dvb_frontend_detach(fe
);
397 int as102_dvb_register_fe(struct as102_dev_t
*as102_dev
,
398 struct dvb_frontend
*dvb_fe
)
401 struct dvb_adapter
*dvb_adap
;
403 if (as102_dev
== NULL
)
406 /* extract dvb_adapter */
407 dvb_adap
= &as102_dev
->dvb_adap
;
409 /* init frontend callback ops */
410 memcpy(&dvb_fe
->ops
, &as102_fe_ops
, sizeof(struct dvb_frontend_ops
));
411 strncpy(dvb_fe
->ops
.info
.name
, as102_dev
->name
,
412 sizeof(dvb_fe
->ops
.info
.name
));
414 /* register dbvb frontend */
415 errno
= dvb_register_frontend(dvb_adap
, dvb_fe
);
417 dvb_fe
->tuner_priv
= as102_dev
;
422 static void as10x_fe_copy_tps_parameters(struct dvb_frontend_parameters
*dst
,
423 struct as10x_tps
*as10x_tps
)
426 struct dvb_ofdm_parameters
*fe_tps
= &dst
->u
.ofdm
;
428 /* extract consteallation */
429 switch (as10x_tps
->constellation
) {
431 fe_tps
->constellation
= QPSK
;
434 fe_tps
->constellation
= QAM_16
;
437 fe_tps
->constellation
= QAM_64
;
441 /* extract hierarchy */
442 switch (as10x_tps
->hierarchy
) {
444 fe_tps
->hierarchy_information
= HIERARCHY_NONE
;
447 fe_tps
->hierarchy_information
= HIERARCHY_1
;
450 fe_tps
->hierarchy_information
= HIERARCHY_2
;
453 fe_tps
->hierarchy_information
= HIERARCHY_4
;
457 /* extract code rate HP */
458 switch (as10x_tps
->code_rate_HP
) {
460 fe_tps
->code_rate_HP
= FEC_1_2
;
463 fe_tps
->code_rate_HP
= FEC_2_3
;
466 fe_tps
->code_rate_HP
= FEC_3_4
;
469 fe_tps
->code_rate_HP
= FEC_5_6
;
472 fe_tps
->code_rate_HP
= FEC_7_8
;
476 /* extract code rate LP */
477 switch (as10x_tps
->code_rate_LP
) {
479 fe_tps
->code_rate_LP
= FEC_1_2
;
482 fe_tps
->code_rate_LP
= FEC_2_3
;
485 fe_tps
->code_rate_LP
= FEC_3_4
;
488 fe_tps
->code_rate_LP
= FEC_5_6
;
491 fe_tps
->code_rate_LP
= FEC_7_8
;
495 /* extract guard interval */
496 switch (as10x_tps
->guard_interval
) {
498 fe_tps
->guard_interval
= GUARD_INTERVAL_1_32
;
501 fe_tps
->guard_interval
= GUARD_INTERVAL_1_16
;
504 fe_tps
->guard_interval
= GUARD_INTERVAL_1_8
;
507 fe_tps
->guard_interval
= GUARD_INTERVAL_1_4
;
511 /* extract transmission mode */
512 switch (as10x_tps
->transmission_mode
) {
514 fe_tps
->transmission_mode
= TRANSMISSION_MODE_2K
;
517 fe_tps
->transmission_mode
= TRANSMISSION_MODE_8K
;
522 static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg
)
543 c
= CODE_RATE_UNKNOWN
;
550 static void as102_fe_copy_tune_parameters(struct as10x_tune_args
*tune_args
,
551 struct dvb_frontend_parameters
*params
)
555 tune_args
->freq
= params
->frequency
/ 1000;
557 /* fix interleaving_mode */
558 tune_args
->interleaving_mode
= INTLV_NATIVE
;
560 switch (params
->u
.ofdm
.bandwidth
) {
561 case BANDWIDTH_8_MHZ
:
562 tune_args
->bandwidth
= BW_8_MHZ
;
564 case BANDWIDTH_7_MHZ
:
565 tune_args
->bandwidth
= BW_7_MHZ
;
567 case BANDWIDTH_6_MHZ
:
568 tune_args
->bandwidth
= BW_6_MHZ
;
571 tune_args
->bandwidth
= BW_8_MHZ
;
574 switch (params
->u
.ofdm
.guard_interval
) {
575 case GUARD_INTERVAL_1_32
:
576 tune_args
->guard_interval
= GUARD_INT_1_32
;
578 case GUARD_INTERVAL_1_16
:
579 tune_args
->guard_interval
= GUARD_INT_1_16
;
581 case GUARD_INTERVAL_1_8
:
582 tune_args
->guard_interval
= GUARD_INT_1_8
;
584 case GUARD_INTERVAL_1_4
:
585 tune_args
->guard_interval
= GUARD_INT_1_4
;
587 case GUARD_INTERVAL_AUTO
:
589 tune_args
->guard_interval
= GUARD_UNKNOWN
;
593 switch (params
->u
.ofdm
.constellation
) {
595 tune_args
->constellation
= CONST_QPSK
;
598 tune_args
->constellation
= CONST_QAM16
;
601 tune_args
->constellation
= CONST_QAM64
;
604 tune_args
->constellation
= CONST_UNKNOWN
;
608 switch (params
->u
.ofdm
.transmission_mode
) {
609 case TRANSMISSION_MODE_2K
:
610 tune_args
->transmission_mode
= TRANS_MODE_2K
;
612 case TRANSMISSION_MODE_8K
:
613 tune_args
->transmission_mode
= TRANS_MODE_8K
;
616 tune_args
->transmission_mode
= TRANS_MODE_UNKNOWN
;
619 switch (params
->u
.ofdm
.hierarchy_information
) {
621 tune_args
->hierarchy
= HIER_NONE
;
624 tune_args
->hierarchy
= HIER_ALPHA_1
;
627 tune_args
->hierarchy
= HIER_ALPHA_2
;
630 tune_args
->hierarchy
= HIER_ALPHA_4
;
633 tune_args
->hierarchy
= HIER_UNKNOWN
;
637 dprintk(debug
, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n",
639 tune_args
->bandwidth
,
640 tune_args
->guard_interval
);
643 * Detect a hierarchy selection
644 * if HP/LP are both set to FEC_NONE, HP will be selected.
646 if ((tune_args
->hierarchy
!= HIER_NONE
) &&
647 ((params
->u
.ofdm
.code_rate_LP
== FEC_NONE
) ||
648 (params
->u
.ofdm
.code_rate_HP
== FEC_NONE
))) {
650 if (params
->u
.ofdm
.code_rate_LP
== FEC_NONE
) {
651 tune_args
->hier_select
= HIER_HIGH_PRIORITY
;
652 tune_args
->code_rate
=
653 as102_fe_get_code_rate(params
->u
.ofdm
.code_rate_HP
);
656 if (params
->u
.ofdm
.code_rate_HP
== FEC_NONE
) {
657 tune_args
->hier_select
= HIER_LOW_PRIORITY
;
658 tune_args
->code_rate
=
659 as102_fe_get_code_rate(params
->u
.ofdm
.code_rate_LP
);
662 dprintk(debug
, "\thierarchy: 0x%02x "
663 "selected: %s code_rate_%s: 0x%02x\n",
664 tune_args
->hierarchy
,
665 tune_args
->hier_select
== HIER_HIGH_PRIORITY
?
667 tune_args
->hier_select
== HIER_HIGH_PRIORITY
?
669 tune_args
->code_rate
);
671 tune_args
->code_rate
=
672 as102_fe_get_code_rate(params
->u
.ofdm
.code_rate_HP
);
677 /* EOF - vim: set textwidth=80 ts=8 sw=8 sts=8 noet: */