1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * TerraTec Cinergy T2/qanu USB2 DVB-T adapter.
5 * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi)
7 * Based on the dvb-usb-framework code and the
8 * original Terratec Cinergy T2 driver by:
10 * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and
11 * Holger Waechtler <holger@qanu.de>
13 * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf
16 #include "cinergyT2.h"
20 * convert linux-dvb frontend parameter set into TPS.
21 * See ETSI ETS-300744, section 4.6.2, table 9 for details.
23 * This function is probably reusable and may better get placed in a support
26 * We replace erroneous fields by default TPS fields (the ones with value 0).
29 static uint16_t compute_tps(struct dtv_frontend_properties
*op
)
33 switch (op
->code_rate_HP
) {
49 /* tps |= (0 << 7) */;
52 switch (op
->code_rate_LP
) {
68 /* tps |= (0 << 4) */;
71 switch (op
->modulation
) {
80 /* tps |= (0 << 13) */;
83 switch (op
->transmission_mode
) {
84 case TRANSMISSION_MODE_8K
:
87 case TRANSMISSION_MODE_2K
:
89 /* tps |= (0 << 0) */;
92 switch (op
->guard_interval
) {
93 case GUARD_INTERVAL_1_16
:
96 case GUARD_INTERVAL_1_8
:
99 case GUARD_INTERVAL_1_4
:
102 case GUARD_INTERVAL_1_32
:
104 /* tps |= (0 << 2) */;
107 switch (op
->hierarchy
) {
119 /* tps |= (0 << 10) */;
125 struct cinergyt2_fe_state
{
126 struct dvb_frontend fe
;
127 struct dvb_usb_device
*d
;
129 unsigned char data
[64];
130 struct mutex data_mutex
;
132 struct dvbt_get_status_msg status
;
135 static int cinergyt2_fe_read_status(struct dvb_frontend
*fe
,
136 enum fe_status
*status
)
138 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
141 mutex_lock(&state
->data_mutex
);
142 state
->data
[0] = CINERGYT2_EP1_GET_TUNER_STATUS
;
144 ret
= dvb_usb_generic_rw(state
->d
, state
->data
, 1,
145 state
->data
, sizeof(state
->status
), 0);
147 memcpy(&state
->status
, state
->data
, sizeof(state
->status
));
148 mutex_unlock(&state
->data_mutex
);
155 if (0xffff - le16_to_cpu(state
->status
.gain
) > 30)
156 *status
|= FE_HAS_SIGNAL
;
157 if (state
->status
.lock_bits
& (1 << 6))
158 *status
|= FE_HAS_LOCK
;
159 if (state
->status
.lock_bits
& (1 << 5))
160 *status
|= FE_HAS_SYNC
;
161 if (state
->status
.lock_bits
& (1 << 4))
162 *status
|= FE_HAS_CARRIER
;
163 if (state
->status
.lock_bits
& (1 << 1))
164 *status
|= FE_HAS_VITERBI
;
166 if ((*status
& (FE_HAS_CARRIER
| FE_HAS_VITERBI
| FE_HAS_SYNC
)) !=
167 (FE_HAS_CARRIER
| FE_HAS_VITERBI
| FE_HAS_SYNC
))
168 *status
&= ~FE_HAS_LOCK
;
173 static int cinergyt2_fe_read_ber(struct dvb_frontend
*fe
, u32
*ber
)
175 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
177 *ber
= le32_to_cpu(state
->status
.viterbi_error_rate
);
181 static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend
*fe
, u32
*unc
)
183 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
185 *unc
= le32_to_cpu(state
->status
.uncorrected_block_count
);
189 static int cinergyt2_fe_read_signal_strength(struct dvb_frontend
*fe
,
192 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
194 *strength
= (0xffff - le16_to_cpu(state
->status
.gain
));
198 static int cinergyt2_fe_read_snr(struct dvb_frontend
*fe
, u16
*snr
)
200 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
202 *snr
= (state
->status
.snr
<< 8) | state
->status
.snr
;
206 static int cinergyt2_fe_init(struct dvb_frontend
*fe
)
211 static int cinergyt2_fe_sleep(struct dvb_frontend
*fe
)
213 deb_info("cinergyt2_fe_sleep() Called\n");
217 static int cinergyt2_fe_get_tune_settings(struct dvb_frontend
*fe
,
218 struct dvb_frontend_tune_settings
*tune
)
220 tune
->min_delay_ms
= 800;
224 static int cinergyt2_fe_set_frontend(struct dvb_frontend
*fe
)
226 struct dtv_frontend_properties
*fep
= &fe
->dtv_property_cache
;
227 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
228 struct dvbt_set_parameters_msg
*param
;
231 mutex_lock(&state
->data_mutex
);
233 param
= (void *)state
->data
;
234 param
->cmd
= CINERGYT2_EP1_SET_TUNER_PARAMETERS
;
235 param
->tps
= cpu_to_le16(compute_tps(fep
));
236 param
->freq
= cpu_to_le32(fep
->frequency
/ 1000);
239 switch (fep
->bandwidth_hz
) {
242 param
->bandwidth
= 8;
245 param
->bandwidth
= 7;
248 param
->bandwidth
= 6;
252 err
= dvb_usb_generic_rw(state
->d
, state
->data
, sizeof(*param
),
255 err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err
);
257 mutex_unlock(&state
->data_mutex
);
258 return (err
< 0) ? err
: 0;
261 static void cinergyt2_fe_release(struct dvb_frontend
*fe
)
263 struct cinergyt2_fe_state
*state
= fe
->demodulator_priv
;
267 static const struct dvb_frontend_ops cinergyt2_fe_ops
;
269 struct dvb_frontend
*cinergyt2_fe_attach(struct dvb_usb_device
*d
)
271 struct cinergyt2_fe_state
*s
= kzalloc(sizeof(
272 struct cinergyt2_fe_state
), GFP_KERNEL
);
277 memcpy(&s
->fe
.ops
, &cinergyt2_fe_ops
, sizeof(struct dvb_frontend_ops
));
278 s
->fe
.demodulator_priv
= s
;
279 mutex_init(&s
->data_mutex
);
284 static const struct dvb_frontend_ops cinergyt2_fe_ops
= {
285 .delsys
= { SYS_DVBT
},
288 .frequency_min_hz
= 174 * MHz
,
289 .frequency_max_hz
= 862 * MHz
,
290 .frequency_stepsize_hz
= 166667,
291 .caps
= FE_CAN_INVERSION_AUTO
| FE_CAN_FEC_1_2
292 | FE_CAN_FEC_2_3
| FE_CAN_FEC_3_4
293 | FE_CAN_FEC_5_6
| FE_CAN_FEC_7_8
294 | FE_CAN_FEC_AUTO
| FE_CAN_QPSK
295 | FE_CAN_QAM_16
| FE_CAN_QAM_64
297 | FE_CAN_TRANSMISSION_MODE_AUTO
298 | FE_CAN_GUARD_INTERVAL_AUTO
299 | FE_CAN_HIERARCHY_AUTO
304 .release
= cinergyt2_fe_release
,
306 .init
= cinergyt2_fe_init
,
307 .sleep
= cinergyt2_fe_sleep
,
309 .set_frontend
= cinergyt2_fe_set_frontend
,
310 .get_tune_settings
= cinergyt2_fe_get_tune_settings
,
312 .read_status
= cinergyt2_fe_read_status
,
313 .read_ber
= cinergyt2_fe_read_ber
,
314 .read_signal_strength
= cinergyt2_fe_read_signal_strength
,
315 .read_snr
= cinergyt2_fe_read_snr
,
316 .read_ucblocks
= cinergyt2_fe_read_unc_blocks
,