1786baecfSMauro Carvalho Chehab /* 2786baecfSMauro Carvalho Chehab * TerraTec Cinergy T2/qanu USB2 DVB-T adapter. 3786baecfSMauro Carvalho Chehab * 4786baecfSMauro Carvalho Chehab * Copyright (C) 2007 Tomi Orava (tomimo@ncircle.nullnet.fi) 5786baecfSMauro Carvalho Chehab * 6786baecfSMauro Carvalho Chehab * Based on the dvb-usb-framework code and the 7786baecfSMauro Carvalho Chehab * original Terratec Cinergy T2 driver by: 8786baecfSMauro Carvalho Chehab * 9786baecfSMauro Carvalho Chehab * Copyright (C) 2004 Daniel Mack <daniel@qanu.de> and 10786baecfSMauro Carvalho Chehab * Holger Waechtler <holger@qanu.de> 11786baecfSMauro Carvalho Chehab * 12786baecfSMauro Carvalho Chehab * Protocol Spec published on http://qanu.de/specs/terratec_cinergyT2.pdf 13786baecfSMauro Carvalho Chehab * 14786baecfSMauro Carvalho Chehab * This program is free software; you can redistribute it and/or modify 15786baecfSMauro Carvalho Chehab * it under the terms of the GNU General Public License as published by 16786baecfSMauro Carvalho Chehab * the Free Software Foundation; either version 2 of the License, or 17786baecfSMauro Carvalho Chehab * (at your option) any later version. 18786baecfSMauro Carvalho Chehab * 19786baecfSMauro Carvalho Chehab * This program is distributed in the hope that it will be useful, 20786baecfSMauro Carvalho Chehab * but WITHOUT ANY WARRANTY; without even the implied warranty of 21786baecfSMauro Carvalho Chehab * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22786baecfSMauro Carvalho Chehab * GNU General Public License for more details. 23786baecfSMauro Carvalho Chehab * 24786baecfSMauro Carvalho Chehab */ 25786baecfSMauro Carvalho Chehab 26786baecfSMauro Carvalho Chehab #include "cinergyT2.h" 27786baecfSMauro Carvalho Chehab 28786baecfSMauro Carvalho Chehab 29cba862dcSMauro Carvalho Chehab /* 30786baecfSMauro Carvalho Chehab * convert linux-dvb frontend parameter set into TPS. 31786baecfSMauro Carvalho Chehab * See ETSI ETS-300744, section 4.6.2, table 9 for details. 32786baecfSMauro Carvalho Chehab * 33786baecfSMauro Carvalho Chehab * This function is probably reusable and may better get placed in a support 34786baecfSMauro Carvalho Chehab * library. 35786baecfSMauro Carvalho Chehab * 363e4d8f48SMauro Carvalho Chehab * We replace erroneous fields by default TPS fields (the ones with value 0). 37786baecfSMauro Carvalho Chehab */ 38786baecfSMauro Carvalho Chehab 39786baecfSMauro Carvalho Chehab static uint16_t compute_tps(struct dtv_frontend_properties *op) 40786baecfSMauro Carvalho Chehab { 41786baecfSMauro Carvalho Chehab uint16_t tps = 0; 42786baecfSMauro Carvalho Chehab 43786baecfSMauro Carvalho Chehab switch (op->code_rate_HP) { 44786baecfSMauro Carvalho Chehab case FEC_2_3: 45786baecfSMauro Carvalho Chehab tps |= (1 << 7); 46786baecfSMauro Carvalho Chehab break; 47786baecfSMauro Carvalho Chehab case FEC_3_4: 48786baecfSMauro Carvalho Chehab tps |= (2 << 7); 49786baecfSMauro Carvalho Chehab break; 50786baecfSMauro Carvalho Chehab case FEC_5_6: 51786baecfSMauro Carvalho Chehab tps |= (3 << 7); 52786baecfSMauro Carvalho Chehab break; 53786baecfSMauro Carvalho Chehab case FEC_7_8: 54786baecfSMauro Carvalho Chehab tps |= (4 << 7); 55786baecfSMauro Carvalho Chehab break; 56786baecfSMauro Carvalho Chehab case FEC_1_2: 57786baecfSMauro Carvalho Chehab case FEC_AUTO: 58786baecfSMauro Carvalho Chehab default: 59786baecfSMauro Carvalho Chehab /* tps |= (0 << 7) */; 60786baecfSMauro Carvalho Chehab } 61786baecfSMauro Carvalho Chehab 62786baecfSMauro Carvalho Chehab switch (op->code_rate_LP) { 63786baecfSMauro Carvalho Chehab case FEC_2_3: 64786baecfSMauro Carvalho Chehab tps |= (1 << 4); 65786baecfSMauro Carvalho Chehab break; 66786baecfSMauro Carvalho Chehab case FEC_3_4: 67786baecfSMauro Carvalho Chehab tps |= (2 << 4); 68786baecfSMauro Carvalho Chehab break; 69786baecfSMauro Carvalho Chehab case FEC_5_6: 70786baecfSMauro Carvalho Chehab tps |= (3 << 4); 71786baecfSMauro Carvalho Chehab break; 72786baecfSMauro Carvalho Chehab case FEC_7_8: 73786baecfSMauro Carvalho Chehab tps |= (4 << 4); 74786baecfSMauro Carvalho Chehab break; 75786baecfSMauro Carvalho Chehab case FEC_1_2: 76786baecfSMauro Carvalho Chehab case FEC_AUTO: 77786baecfSMauro Carvalho Chehab default: 78786baecfSMauro Carvalho Chehab /* tps |= (0 << 4) */; 79786baecfSMauro Carvalho Chehab } 80786baecfSMauro Carvalho Chehab 81786baecfSMauro Carvalho Chehab switch (op->modulation) { 82786baecfSMauro Carvalho Chehab case QAM_16: 83786baecfSMauro Carvalho Chehab tps |= (1 << 13); 84786baecfSMauro Carvalho Chehab break; 85786baecfSMauro Carvalho Chehab case QAM_64: 86786baecfSMauro Carvalho Chehab tps |= (2 << 13); 87786baecfSMauro Carvalho Chehab break; 88786baecfSMauro Carvalho Chehab case QPSK: 89786baecfSMauro Carvalho Chehab default: 90786baecfSMauro Carvalho Chehab /* tps |= (0 << 13) */; 91786baecfSMauro Carvalho Chehab } 92786baecfSMauro Carvalho Chehab 93786baecfSMauro Carvalho Chehab switch (op->transmission_mode) { 94786baecfSMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 95786baecfSMauro Carvalho Chehab tps |= (1 << 0); 96786baecfSMauro Carvalho Chehab break; 97786baecfSMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 98786baecfSMauro Carvalho Chehab default: 99786baecfSMauro Carvalho Chehab /* tps |= (0 << 0) */; 100786baecfSMauro Carvalho Chehab } 101786baecfSMauro Carvalho Chehab 102786baecfSMauro Carvalho Chehab switch (op->guard_interval) { 103786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 104786baecfSMauro Carvalho Chehab tps |= (1 << 2); 105786baecfSMauro Carvalho Chehab break; 106786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 107786baecfSMauro Carvalho Chehab tps |= (2 << 2); 108786baecfSMauro Carvalho Chehab break; 109786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 110786baecfSMauro Carvalho Chehab tps |= (3 << 2); 111786baecfSMauro Carvalho Chehab break; 112786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 113786baecfSMauro Carvalho Chehab default: 114786baecfSMauro Carvalho Chehab /* tps |= (0 << 2) */; 115786baecfSMauro Carvalho Chehab } 116786baecfSMauro Carvalho Chehab 117786baecfSMauro Carvalho Chehab switch (op->hierarchy) { 118786baecfSMauro Carvalho Chehab case HIERARCHY_1: 119786baecfSMauro Carvalho Chehab tps |= (1 << 10); 120786baecfSMauro Carvalho Chehab break; 121786baecfSMauro Carvalho Chehab case HIERARCHY_2: 122786baecfSMauro Carvalho Chehab tps |= (2 << 10); 123786baecfSMauro Carvalho Chehab break; 124786baecfSMauro Carvalho Chehab case HIERARCHY_4: 125786baecfSMauro Carvalho Chehab tps |= (3 << 10); 126786baecfSMauro Carvalho Chehab break; 127786baecfSMauro Carvalho Chehab case HIERARCHY_NONE: 128786baecfSMauro Carvalho Chehab default: 129786baecfSMauro Carvalho Chehab /* tps |= (0 << 10) */; 130786baecfSMauro Carvalho Chehab } 131786baecfSMauro Carvalho Chehab 132786baecfSMauro Carvalho Chehab return tps; 133786baecfSMauro Carvalho Chehab } 134786baecfSMauro Carvalho Chehab 135786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state { 136786baecfSMauro Carvalho Chehab struct dvb_frontend fe; 137786baecfSMauro Carvalho Chehab struct dvb_usb_device *d; 1380d43c0ffSMauro Carvalho Chehab 1390d43c0ffSMauro Carvalho Chehab unsigned char data[64]; 1400d43c0ffSMauro Carvalho Chehab struct mutex data_mutex; 1410d43c0ffSMauro Carvalho Chehab 142c2730eefSMauro Carvalho Chehab struct dvbt_get_status_msg status; 143786baecfSMauro Carvalho Chehab }; 144786baecfSMauro Carvalho Chehab 145786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_status(struct dvb_frontend *fe, 1460df289a2SMauro Carvalho Chehab enum fe_status *status) 147786baecfSMauro Carvalho Chehab { 148786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 149786baecfSMauro Carvalho Chehab int ret; 150786baecfSMauro Carvalho Chehab 1510d43c0ffSMauro Carvalho Chehab mutex_lock(&state->data_mutex); 1520d43c0ffSMauro Carvalho Chehab state->data[0] = CINERGYT2_EP1_GET_TUNER_STATUS; 1530d43c0ffSMauro Carvalho Chehab 1540d43c0ffSMauro Carvalho Chehab ret = dvb_usb_generic_rw(state->d, state->data, 1, 1550d43c0ffSMauro Carvalho Chehab state->data, sizeof(state->status), 0); 1560d43c0ffSMauro Carvalho Chehab if (!ret) 1570d43c0ffSMauro Carvalho Chehab memcpy(&state->status, state->data, sizeof(state->status)); 1580d43c0ffSMauro Carvalho Chehab mutex_unlock(&state->data_mutex); 1590d43c0ffSMauro Carvalho Chehab 160786baecfSMauro Carvalho Chehab if (ret < 0) 161786baecfSMauro Carvalho Chehab return ret; 162786baecfSMauro Carvalho Chehab 163786baecfSMauro Carvalho Chehab *status = 0; 164786baecfSMauro Carvalho Chehab 1650d43c0ffSMauro Carvalho Chehab if (0xffff - le16_to_cpu(state->status.gain) > 30) 166786baecfSMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 1670d43c0ffSMauro Carvalho Chehab if (state->status.lock_bits & (1 << 6)) 168786baecfSMauro Carvalho Chehab *status |= FE_HAS_LOCK; 1690d43c0ffSMauro Carvalho Chehab if (state->status.lock_bits & (1 << 5)) 170786baecfSMauro Carvalho Chehab *status |= FE_HAS_SYNC; 1710d43c0ffSMauro Carvalho Chehab if (state->status.lock_bits & (1 << 4)) 172786baecfSMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 1730d43c0ffSMauro Carvalho Chehab if (state->status.lock_bits & (1 << 1)) 174786baecfSMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 175786baecfSMauro Carvalho Chehab 176786baecfSMauro Carvalho Chehab if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != 177786baecfSMauro Carvalho Chehab (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) 178786baecfSMauro Carvalho Chehab *status &= ~FE_HAS_LOCK; 179786baecfSMauro Carvalho Chehab 180786baecfSMauro Carvalho Chehab return 0; 181786baecfSMauro Carvalho Chehab } 182786baecfSMauro Carvalho Chehab 183786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) 184786baecfSMauro Carvalho Chehab { 185786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 186786baecfSMauro Carvalho Chehab 187c2730eefSMauro Carvalho Chehab *ber = le32_to_cpu(state->status.viterbi_error_rate); 188786baecfSMauro Carvalho Chehab return 0; 189786baecfSMauro Carvalho Chehab } 190786baecfSMauro Carvalho Chehab 191786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) 192786baecfSMauro Carvalho Chehab { 193786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 194786baecfSMauro Carvalho Chehab 195c2730eefSMauro Carvalho Chehab *unc = le32_to_cpu(state->status.uncorrected_block_count); 196786baecfSMauro Carvalho Chehab return 0; 197786baecfSMauro Carvalho Chehab } 198786baecfSMauro Carvalho Chehab 199786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, 200786baecfSMauro Carvalho Chehab u16 *strength) 201786baecfSMauro Carvalho Chehab { 202786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 203786baecfSMauro Carvalho Chehab 204c2730eefSMauro Carvalho Chehab *strength = (0xffff - le16_to_cpu(state->status.gain)); 205786baecfSMauro Carvalho Chehab return 0; 206786baecfSMauro Carvalho Chehab } 207786baecfSMauro Carvalho Chehab 208786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) 209786baecfSMauro Carvalho Chehab { 210786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 211786baecfSMauro Carvalho Chehab 212c2730eefSMauro Carvalho Chehab *snr = (state->status.snr << 8) | state->status.snr; 213786baecfSMauro Carvalho Chehab return 0; 214786baecfSMauro Carvalho Chehab } 215786baecfSMauro Carvalho Chehab 216786baecfSMauro Carvalho Chehab static int cinergyt2_fe_init(struct dvb_frontend *fe) 217786baecfSMauro Carvalho Chehab { 218786baecfSMauro Carvalho Chehab return 0; 219786baecfSMauro Carvalho Chehab } 220786baecfSMauro Carvalho Chehab 221786baecfSMauro Carvalho Chehab static int cinergyt2_fe_sleep(struct dvb_frontend *fe) 222786baecfSMauro Carvalho Chehab { 223786baecfSMauro Carvalho Chehab deb_info("cinergyt2_fe_sleep() Called\n"); 224786baecfSMauro Carvalho Chehab return 0; 225786baecfSMauro Carvalho Chehab } 226786baecfSMauro Carvalho Chehab 227786baecfSMauro Carvalho Chehab static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, 228786baecfSMauro Carvalho Chehab struct dvb_frontend_tune_settings *tune) 229786baecfSMauro Carvalho Chehab { 230786baecfSMauro Carvalho Chehab tune->min_delay_ms = 800; 231786baecfSMauro Carvalho Chehab return 0; 232786baecfSMauro Carvalho Chehab } 233786baecfSMauro Carvalho Chehab 234786baecfSMauro Carvalho Chehab static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) 235786baecfSMauro Carvalho Chehab { 236786baecfSMauro Carvalho Chehab struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 237786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 2380d43c0ffSMauro Carvalho Chehab struct dvbt_set_parameters_msg *param; 239786baecfSMauro Carvalho Chehab int err; 240786baecfSMauro Carvalho Chehab 2410d43c0ffSMauro Carvalho Chehab mutex_lock(&state->data_mutex); 2420d43c0ffSMauro Carvalho Chehab 2430d43c0ffSMauro Carvalho Chehab param = (void *)state->data; 2440d43c0ffSMauro Carvalho Chehab param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; 2450d43c0ffSMauro Carvalho Chehab param->tps = cpu_to_le16(compute_tps(fep)); 2460d43c0ffSMauro Carvalho Chehab param->freq = cpu_to_le32(fep->frequency / 1000); 2470d43c0ffSMauro Carvalho Chehab param->flags = 0; 248786baecfSMauro Carvalho Chehab 249786baecfSMauro Carvalho Chehab switch (fep->bandwidth_hz) { 250786baecfSMauro Carvalho Chehab default: 251786baecfSMauro Carvalho Chehab case 8000000: 2520d43c0ffSMauro Carvalho Chehab param->bandwidth = 8; 253786baecfSMauro Carvalho Chehab break; 254786baecfSMauro Carvalho Chehab case 7000000: 2550d43c0ffSMauro Carvalho Chehab param->bandwidth = 7; 256786baecfSMauro Carvalho Chehab break; 257786baecfSMauro Carvalho Chehab case 6000000: 2580d43c0ffSMauro Carvalho Chehab param->bandwidth = 6; 259786baecfSMauro Carvalho Chehab break; 260786baecfSMauro Carvalho Chehab } 261786baecfSMauro Carvalho Chehab 2620d43c0ffSMauro Carvalho Chehab err = dvb_usb_generic_rw(state->d, state->data, sizeof(*param), 2630d43c0ffSMauro Carvalho Chehab state->data, 2, 0); 264786baecfSMauro Carvalho Chehab if (err < 0) 265786baecfSMauro Carvalho Chehab err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); 266786baecfSMauro Carvalho Chehab 2670d43c0ffSMauro Carvalho Chehab mutex_unlock(&state->data_mutex); 268786baecfSMauro Carvalho Chehab return (err < 0) ? err : 0; 269786baecfSMauro Carvalho Chehab } 270786baecfSMauro Carvalho Chehab 271786baecfSMauro Carvalho Chehab static void cinergyt2_fe_release(struct dvb_frontend *fe) 272786baecfSMauro Carvalho Chehab { 273786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 274786baecfSMauro Carvalho Chehab kfree(state); 275786baecfSMauro Carvalho Chehab } 276786baecfSMauro Carvalho Chehab 277bd336e63SMax Kellermann static const struct dvb_frontend_ops cinergyt2_fe_ops; 278786baecfSMauro Carvalho Chehab 279786baecfSMauro Carvalho Chehab struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) 280786baecfSMauro Carvalho Chehab { 281786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *s = kzalloc(sizeof( 282786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state), GFP_KERNEL); 283786baecfSMauro Carvalho Chehab if (s == NULL) 284786baecfSMauro Carvalho Chehab return NULL; 285786baecfSMauro Carvalho Chehab 286786baecfSMauro Carvalho Chehab s->d = d; 287786baecfSMauro Carvalho Chehab memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); 288786baecfSMauro Carvalho Chehab s->fe.demodulator_priv = s; 2890d43c0ffSMauro Carvalho Chehab mutex_init(&s->data_mutex); 290786baecfSMauro Carvalho Chehab return &s->fe; 291786baecfSMauro Carvalho Chehab } 292786baecfSMauro Carvalho Chehab 293786baecfSMauro Carvalho Chehab 294bd336e63SMax Kellermann static const struct dvb_frontend_ops cinergyt2_fe_ops = { 295786baecfSMauro Carvalho Chehab .delsys = { SYS_DVBT }, 296786baecfSMauro Carvalho Chehab .info = { 297786baecfSMauro Carvalho Chehab .name = DRIVER_NAME, 298f1b1eabfSMauro Carvalho Chehab .frequency_min_hz = 174 * MHz, 299f1b1eabfSMauro Carvalho Chehab .frequency_max_hz = 862 * MHz, 300f1b1eabfSMauro Carvalho Chehab .frequency_stepsize_hz = 166667, 301786baecfSMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 302786baecfSMauro Carvalho Chehab | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 303786baecfSMauro Carvalho Chehab | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 304786baecfSMauro Carvalho Chehab | FE_CAN_FEC_AUTO | FE_CAN_QPSK 305786baecfSMauro Carvalho Chehab | FE_CAN_QAM_16 | FE_CAN_QAM_64 306786baecfSMauro Carvalho Chehab | FE_CAN_QAM_AUTO 307786baecfSMauro Carvalho Chehab | FE_CAN_TRANSMISSION_MODE_AUTO 308786baecfSMauro Carvalho Chehab | FE_CAN_GUARD_INTERVAL_AUTO 309786baecfSMauro Carvalho Chehab | FE_CAN_HIERARCHY_AUTO 310786baecfSMauro Carvalho Chehab | FE_CAN_RECOVER 311786baecfSMauro Carvalho Chehab | FE_CAN_MUTE_TS 312786baecfSMauro Carvalho Chehab }, 313786baecfSMauro Carvalho Chehab 314786baecfSMauro Carvalho Chehab .release = cinergyt2_fe_release, 315786baecfSMauro Carvalho Chehab 316786baecfSMauro Carvalho Chehab .init = cinergyt2_fe_init, 317786baecfSMauro Carvalho Chehab .sleep = cinergyt2_fe_sleep, 318786baecfSMauro Carvalho Chehab 319786baecfSMauro Carvalho Chehab .set_frontend = cinergyt2_fe_set_frontend, 320786baecfSMauro Carvalho Chehab .get_tune_settings = cinergyt2_fe_get_tune_settings, 321786baecfSMauro Carvalho Chehab 322786baecfSMauro Carvalho Chehab .read_status = cinergyt2_fe_read_status, 323786baecfSMauro Carvalho Chehab .read_ber = cinergyt2_fe_read_ber, 324786baecfSMauro Carvalho Chehab .read_signal_strength = cinergyt2_fe_read_signal_strength, 325786baecfSMauro Carvalho Chehab .read_snr = cinergyt2_fe_read_snr, 326786baecfSMauro Carvalho Chehab .read_ucblocks = cinergyt2_fe_read_unc_blocks, 327786baecfSMauro Carvalho Chehab }; 328