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 "as102_drv.h"
21 #include "as10x_types.h"
22 #include "as10x_cmd.h"
24 static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties
*dst
,
25 struct as10x_tps
*src
);
27 static void as102_fe_copy_tune_parameters(struct as10x_tune_args
*dst
,
28 struct dtv_frontend_properties
*src
);
30 static int as102_fe_set_frontend(struct dvb_frontend
*fe
)
32 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
34 struct as102_dev_t
*dev
;
35 struct as10x_tune_args tune_args
= { 0 };
39 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
43 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
46 as102_fe_copy_tune_parameters(&tune_args
, p
);
48 /* send abilis command: SET_TUNE */
49 ret
= as10x_cmd_set_tune(&dev
->bus_adap
, &tune_args
);
51 dprintk(debug
, "as10x_cmd_set_tune failed. (err = %d)\n", ret
);
53 mutex_unlock(&dev
->bus_adap
.lock
);
56 return (ret
< 0) ? -EINVAL
: 0;
59 static int as102_fe_get_frontend(struct dvb_frontend
*fe
)
61 struct dtv_frontend_properties
*p
= &fe
->dtv_property_cache
;
63 struct as102_dev_t
*dev
;
64 struct as10x_tps tps
= { 0 };
68 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
72 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
75 /* send abilis command: GET_TPS */
76 ret
= as10x_cmd_get_tps(&dev
->bus_adap
, &tps
);
79 as10x_fe_copy_tps_parameters(p
, &tps
);
81 mutex_unlock(&dev
->bus_adap
.lock
);
84 return (ret
< 0) ? -EINVAL
: 0;
87 static int as102_fe_get_tune_settings(struct dvb_frontend
*fe
,
88 struct dvb_frontend_tune_settings
*settings
) {
92 dprintk(debug
, "step_size = %d\n", settings
->step_size
);
93 dprintk(debug
, "max_drift = %d\n", settings
->max_drift
);
94 dprintk(debug
, "min_delay_ms = %d -> %d\n", settings
->min_delay_ms
,
98 settings
->min_delay_ms
= 1000;
105 static int as102_fe_read_status(struct dvb_frontend
*fe
, fe_status_t
*status
)
108 struct as102_dev_t
*dev
;
109 struct as10x_tune_status tstate
= { 0 };
113 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
117 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
120 /* send abilis command: GET_TUNE_STATUS */
121 ret
= as10x_cmd_get_tune_status(&dev
->bus_adap
, &tstate
);
123 dprintk(debug
, "as10x_cmd_get_tune_status failed (err = %d)\n",
128 dev
->signal_strength
= tstate
.signal_strength
;
129 dev
->ber
= tstate
.BER
;
131 switch (tstate
.tune_state
) {
132 case TUNE_STATUS_SIGNAL_DVB_OK
:
133 *status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
;
135 case TUNE_STATUS_STREAM_DETECTED
:
136 *status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_SYNC
;
138 case TUNE_STATUS_STREAM_TUNED
:
139 *status
= FE_HAS_SIGNAL
| FE_HAS_CARRIER
| FE_HAS_SYNC
|
143 *status
= TUNE_STATUS_NOT_TUNED
;
146 dprintk(debug
, "tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
147 tstate
.tune_state
, tstate
.signal_strength
,
148 tstate
.PER
, tstate
.BER
);
150 if (*status
& FE_HAS_LOCK
) {
151 if (as10x_cmd_get_demod_stats(&dev
->bus_adap
,
152 (struct as10x_demod_stats
*) &dev
->demod_stats
) < 0) {
153 memset(&dev
->demod_stats
, 0, sizeof(dev
->demod_stats
));
154 dprintk(debug
, "as10x_cmd_get_demod_stats failed "
155 "(probably not tuned)\n");
158 "demod status: fc: 0x%08x, bad fc: 0x%08x, "
159 "bytes corrected: 0x%08x , MER: 0x%04x\n",
160 dev
->demod_stats
.frame_count
,
161 dev
->demod_stats
.bad_frame_count
,
162 dev
->demod_stats
.bytes_fixed_by_rs
,
163 dev
->demod_stats
.mer
);
166 memset(&dev
->demod_stats
, 0, sizeof(dev
->demod_stats
));
170 mutex_unlock(&dev
->bus_adap
.lock
);
178 * - the SNR will be returned in linear terms, i.e. not in dB
179 * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB
180 * - the accuracy is >2dB for SNR values outside this range
182 static int as102_fe_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
184 struct as102_dev_t
*dev
;
188 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
192 *snr
= dev
->demod_stats
.mer
;
198 static int as102_fe_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
200 struct as102_dev_t
*dev
;
204 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
214 static int as102_fe_read_signal_strength(struct dvb_frontend
*fe
,
217 struct as102_dev_t
*dev
;
221 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
225 *strength
= (((0xffff * 400) * dev
->signal_strength
+ 41000) * 2);
231 static int as102_fe_read_ucblocks(struct dvb_frontend
*fe
, u32
*ucblocks
)
233 struct as102_dev_t
*dev
;
237 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
241 if (dev
->demod_stats
.has_started
)
242 *ucblocks
= dev
->demod_stats
.bad_frame_count
;
250 static int as102_fe_ts_bus_ctrl(struct dvb_frontend
*fe
, int acquire
)
252 struct as102_dev_t
*dev
;
257 dev
= (struct as102_dev_t
*) fe
->tuner_priv
;
261 if (mutex_lock_interruptible(&dev
->bus_adap
.lock
))
266 as10x_cmd_set_context(&dev
->bus_adap
, CONTEXT_LNA
, dev
->elna_cfg
);
268 ret
= as10x_cmd_turn_on(&dev
->bus_adap
);
270 ret
= as10x_cmd_turn_off(&dev
->bus_adap
);
273 mutex_unlock(&dev
->bus_adap
.lock
);
279 static struct dvb_frontend_ops as102_fe_ops
= {
280 .delsys
= { SYS_DVBT
},
282 .name
= "Unknown AS102 device",
283 .frequency_min
= 174000000,
284 .frequency_max
= 862000000,
285 .frequency_stepsize
= 166667,
286 .caps
= FE_CAN_INVERSION_AUTO
287 | FE_CAN_FEC_1_2
| FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
288 | FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
| FE_CAN_FEC_AUTO
289 | FE_CAN_QAM_16
| FE_CAN_QAM_64
| FE_CAN_QPSK
291 | FE_CAN_TRANSMISSION_MODE_AUTO
292 | FE_CAN_GUARD_INTERVAL_AUTO
293 | FE_CAN_HIERARCHY_AUTO
298 .set_frontend
= as102_fe_set_frontend
,
299 .get_frontend
= as102_fe_get_frontend
,
300 .get_tune_settings
= as102_fe_get_tune_settings
,
302 .read_status
= as102_fe_read_status
,
303 .read_snr
= as102_fe_read_snr
,
304 .read_ber
= as102_fe_read_ber
,
305 .read_signal_strength
= as102_fe_read_signal_strength
,
306 .read_ucblocks
= as102_fe_read_ucblocks
,
307 .ts_bus_ctrl
= as102_fe_ts_bus_ctrl
,
310 int as102_dvb_unregister_fe(struct dvb_frontend
*fe
)
312 /* unregister frontend */
313 dvb_unregister_frontend(fe
);
315 /* detach frontend */
316 dvb_frontend_detach(fe
);
321 int as102_dvb_register_fe(struct as102_dev_t
*as102_dev
,
322 struct dvb_frontend
*dvb_fe
)
325 struct dvb_adapter
*dvb_adap
;
327 if (as102_dev
== NULL
)
330 /* extract dvb_adapter */
331 dvb_adap
= &as102_dev
->dvb_adap
;
333 /* init frontend callback ops */
334 memcpy(&dvb_fe
->ops
, &as102_fe_ops
, sizeof(struct dvb_frontend_ops
));
335 strncpy(dvb_fe
->ops
.info
.name
, as102_dev
->name
,
336 sizeof(dvb_fe
->ops
.info
.name
));
338 /* register dvb frontend */
339 errno
= dvb_register_frontend(dvb_adap
, dvb_fe
);
341 dvb_fe
->tuner_priv
= as102_dev
;
346 static void as10x_fe_copy_tps_parameters(struct dtv_frontend_properties
*fe_tps
,
347 struct as10x_tps
*as10x_tps
)
350 /* extract constellation */
351 switch (as10x_tps
->modulation
) {
353 fe_tps
->modulation
= QPSK
;
356 fe_tps
->modulation
= QAM_16
;
359 fe_tps
->modulation
= QAM_64
;
363 /* extract hierarchy */
364 switch (as10x_tps
->hierarchy
) {
366 fe_tps
->hierarchy
= HIERARCHY_NONE
;
369 fe_tps
->hierarchy
= HIERARCHY_1
;
372 fe_tps
->hierarchy
= HIERARCHY_2
;
375 fe_tps
->hierarchy
= HIERARCHY_4
;
379 /* extract code rate HP */
380 switch (as10x_tps
->code_rate_HP
) {
382 fe_tps
->code_rate_HP
= FEC_1_2
;
385 fe_tps
->code_rate_HP
= FEC_2_3
;
388 fe_tps
->code_rate_HP
= FEC_3_4
;
391 fe_tps
->code_rate_HP
= FEC_5_6
;
394 fe_tps
->code_rate_HP
= FEC_7_8
;
398 /* extract code rate LP */
399 switch (as10x_tps
->code_rate_LP
) {
401 fe_tps
->code_rate_LP
= FEC_1_2
;
404 fe_tps
->code_rate_LP
= FEC_2_3
;
407 fe_tps
->code_rate_LP
= FEC_3_4
;
410 fe_tps
->code_rate_LP
= FEC_5_6
;
413 fe_tps
->code_rate_LP
= FEC_7_8
;
417 /* extract guard interval */
418 switch (as10x_tps
->guard_interval
) {
420 fe_tps
->guard_interval
= GUARD_INTERVAL_1_32
;
423 fe_tps
->guard_interval
= GUARD_INTERVAL_1_16
;
426 fe_tps
->guard_interval
= GUARD_INTERVAL_1_8
;
429 fe_tps
->guard_interval
= GUARD_INTERVAL_1_4
;
433 /* extract transmission mode */
434 switch (as10x_tps
->transmission_mode
) {
436 fe_tps
->transmission_mode
= TRANSMISSION_MODE_2K
;
439 fe_tps
->transmission_mode
= TRANSMISSION_MODE_8K
;
444 static uint8_t as102_fe_get_code_rate(fe_code_rate_t arg
)
465 c
= CODE_RATE_UNKNOWN
;
472 static void as102_fe_copy_tune_parameters(struct as10x_tune_args
*tune_args
,
473 struct dtv_frontend_properties
*params
)
477 tune_args
->freq
= params
->frequency
/ 1000;
479 /* fix interleaving_mode */
480 tune_args
->interleaving_mode
= INTLV_NATIVE
;
482 switch (params
->bandwidth_hz
) {
484 tune_args
->bandwidth
= BW_8_MHZ
;
487 tune_args
->bandwidth
= BW_7_MHZ
;
490 tune_args
->bandwidth
= BW_6_MHZ
;
493 tune_args
->bandwidth
= BW_8_MHZ
;
496 switch (params
->guard_interval
) {
497 case GUARD_INTERVAL_1_32
:
498 tune_args
->guard_interval
= GUARD_INT_1_32
;
500 case GUARD_INTERVAL_1_16
:
501 tune_args
->guard_interval
= GUARD_INT_1_16
;
503 case GUARD_INTERVAL_1_8
:
504 tune_args
->guard_interval
= GUARD_INT_1_8
;
506 case GUARD_INTERVAL_1_4
:
507 tune_args
->guard_interval
= GUARD_INT_1_4
;
509 case GUARD_INTERVAL_AUTO
:
511 tune_args
->guard_interval
= GUARD_UNKNOWN
;
515 switch (params
->modulation
) {
517 tune_args
->modulation
= CONST_QPSK
;
520 tune_args
->modulation
= CONST_QAM16
;
523 tune_args
->modulation
= CONST_QAM64
;
526 tune_args
->modulation
= CONST_UNKNOWN
;
530 switch (params
->transmission_mode
) {
531 case TRANSMISSION_MODE_2K
:
532 tune_args
->transmission_mode
= TRANS_MODE_2K
;
534 case TRANSMISSION_MODE_8K
:
535 tune_args
->transmission_mode
= TRANS_MODE_8K
;
538 tune_args
->transmission_mode
= TRANS_MODE_UNKNOWN
;
541 switch (params
->hierarchy
) {
543 tune_args
->hierarchy
= HIER_NONE
;
546 tune_args
->hierarchy
= HIER_ALPHA_1
;
549 tune_args
->hierarchy
= HIER_ALPHA_2
;
552 tune_args
->hierarchy
= HIER_ALPHA_4
;
555 tune_args
->hierarchy
= HIER_UNKNOWN
;
559 dprintk(debug
, "tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n",
561 tune_args
->bandwidth
,
562 tune_args
->guard_interval
);
565 * Detect a hierarchy selection
566 * if HP/LP are both set to FEC_NONE, HP will be selected.
568 if ((tune_args
->hierarchy
!= HIER_NONE
) &&
569 ((params
->code_rate_LP
== FEC_NONE
) ||
570 (params
->code_rate_HP
== FEC_NONE
))) {
572 if (params
->code_rate_LP
== FEC_NONE
) {
573 tune_args
->hier_select
= HIER_HIGH_PRIORITY
;
574 tune_args
->code_rate
=
575 as102_fe_get_code_rate(params
->code_rate_HP
);
578 if (params
->code_rate_HP
== FEC_NONE
) {
579 tune_args
->hier_select
= HIER_LOW_PRIORITY
;
580 tune_args
->code_rate
=
581 as102_fe_get_code_rate(params
->code_rate_LP
);
584 dprintk(debug
, "\thierarchy: 0x%02x "
585 "selected: %s code_rate_%s: 0x%02x\n",
586 tune_args
->hierarchy
,
587 tune_args
->hier_select
== HIER_HIGH_PRIORITY
?
589 tune_args
->hier_select
== HIER_HIGH_PRIORITY
?
591 tune_args
->code_rate
);
593 tune_args
->code_rate
=
594 as102_fe_get_code_rate(params
->code_rate_HP
);