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 * You should have received a copy of the GNU General Public License 25786baecfSMauro Carvalho Chehab * along with this program; if not, write to the Free Software 26786baecfSMauro Carvalho Chehab * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 27786baecfSMauro Carvalho Chehab * 28786baecfSMauro Carvalho Chehab */ 29786baecfSMauro Carvalho Chehab 30786baecfSMauro Carvalho Chehab #include "cinergyT2.h" 31786baecfSMauro Carvalho Chehab 32786baecfSMauro Carvalho Chehab 33786baecfSMauro Carvalho Chehab /** 34786baecfSMauro Carvalho Chehab * convert linux-dvb frontend parameter set into TPS. 35786baecfSMauro Carvalho Chehab * See ETSI ETS-300744, section 4.6.2, table 9 for details. 36786baecfSMauro Carvalho Chehab * 37786baecfSMauro Carvalho Chehab * This function is probably reusable and may better get placed in a support 38786baecfSMauro Carvalho Chehab * library. 39786baecfSMauro Carvalho Chehab * 40786baecfSMauro Carvalho Chehab * We replace errornous fields by default TPS fields (the ones with value 0). 41786baecfSMauro Carvalho Chehab */ 42786baecfSMauro Carvalho Chehab 43786baecfSMauro Carvalho Chehab static uint16_t compute_tps(struct dtv_frontend_properties *op) 44786baecfSMauro Carvalho Chehab { 45786baecfSMauro Carvalho Chehab uint16_t tps = 0; 46786baecfSMauro Carvalho Chehab 47786baecfSMauro Carvalho Chehab switch (op->code_rate_HP) { 48786baecfSMauro Carvalho Chehab case FEC_2_3: 49786baecfSMauro Carvalho Chehab tps |= (1 << 7); 50786baecfSMauro Carvalho Chehab break; 51786baecfSMauro Carvalho Chehab case FEC_3_4: 52786baecfSMauro Carvalho Chehab tps |= (2 << 7); 53786baecfSMauro Carvalho Chehab break; 54786baecfSMauro Carvalho Chehab case FEC_5_6: 55786baecfSMauro Carvalho Chehab tps |= (3 << 7); 56786baecfSMauro Carvalho Chehab break; 57786baecfSMauro Carvalho Chehab case FEC_7_8: 58786baecfSMauro Carvalho Chehab tps |= (4 << 7); 59786baecfSMauro Carvalho Chehab break; 60786baecfSMauro Carvalho Chehab case FEC_1_2: 61786baecfSMauro Carvalho Chehab case FEC_AUTO: 62786baecfSMauro Carvalho Chehab default: 63786baecfSMauro Carvalho Chehab /* tps |= (0 << 7) */; 64786baecfSMauro Carvalho Chehab } 65786baecfSMauro Carvalho Chehab 66786baecfSMauro Carvalho Chehab switch (op->code_rate_LP) { 67786baecfSMauro Carvalho Chehab case FEC_2_3: 68786baecfSMauro Carvalho Chehab tps |= (1 << 4); 69786baecfSMauro Carvalho Chehab break; 70786baecfSMauro Carvalho Chehab case FEC_3_4: 71786baecfSMauro Carvalho Chehab tps |= (2 << 4); 72786baecfSMauro Carvalho Chehab break; 73786baecfSMauro Carvalho Chehab case FEC_5_6: 74786baecfSMauro Carvalho Chehab tps |= (3 << 4); 75786baecfSMauro Carvalho Chehab break; 76786baecfSMauro Carvalho Chehab case FEC_7_8: 77786baecfSMauro Carvalho Chehab tps |= (4 << 4); 78786baecfSMauro Carvalho Chehab break; 79786baecfSMauro Carvalho Chehab case FEC_1_2: 80786baecfSMauro Carvalho Chehab case FEC_AUTO: 81786baecfSMauro Carvalho Chehab default: 82786baecfSMauro Carvalho Chehab /* tps |= (0 << 4) */; 83786baecfSMauro Carvalho Chehab } 84786baecfSMauro Carvalho Chehab 85786baecfSMauro Carvalho Chehab switch (op->modulation) { 86786baecfSMauro Carvalho Chehab case QAM_16: 87786baecfSMauro Carvalho Chehab tps |= (1 << 13); 88786baecfSMauro Carvalho Chehab break; 89786baecfSMauro Carvalho Chehab case QAM_64: 90786baecfSMauro Carvalho Chehab tps |= (2 << 13); 91786baecfSMauro Carvalho Chehab break; 92786baecfSMauro Carvalho Chehab case QPSK: 93786baecfSMauro Carvalho Chehab default: 94786baecfSMauro Carvalho Chehab /* tps |= (0 << 13) */; 95786baecfSMauro Carvalho Chehab } 96786baecfSMauro Carvalho Chehab 97786baecfSMauro Carvalho Chehab switch (op->transmission_mode) { 98786baecfSMauro Carvalho Chehab case TRANSMISSION_MODE_8K: 99786baecfSMauro Carvalho Chehab tps |= (1 << 0); 100786baecfSMauro Carvalho Chehab break; 101786baecfSMauro Carvalho Chehab case TRANSMISSION_MODE_2K: 102786baecfSMauro Carvalho Chehab default: 103786baecfSMauro Carvalho Chehab /* tps |= (0 << 0) */; 104786baecfSMauro Carvalho Chehab } 105786baecfSMauro Carvalho Chehab 106786baecfSMauro Carvalho Chehab switch (op->guard_interval) { 107786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_16: 108786baecfSMauro Carvalho Chehab tps |= (1 << 2); 109786baecfSMauro Carvalho Chehab break; 110786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_8: 111786baecfSMauro Carvalho Chehab tps |= (2 << 2); 112786baecfSMauro Carvalho Chehab break; 113786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_4: 114786baecfSMauro Carvalho Chehab tps |= (3 << 2); 115786baecfSMauro Carvalho Chehab break; 116786baecfSMauro Carvalho Chehab case GUARD_INTERVAL_1_32: 117786baecfSMauro Carvalho Chehab default: 118786baecfSMauro Carvalho Chehab /* tps |= (0 << 2) */; 119786baecfSMauro Carvalho Chehab } 120786baecfSMauro Carvalho Chehab 121786baecfSMauro Carvalho Chehab switch (op->hierarchy) { 122786baecfSMauro Carvalho Chehab case HIERARCHY_1: 123786baecfSMauro Carvalho Chehab tps |= (1 << 10); 124786baecfSMauro Carvalho Chehab break; 125786baecfSMauro Carvalho Chehab case HIERARCHY_2: 126786baecfSMauro Carvalho Chehab tps |= (2 << 10); 127786baecfSMauro Carvalho Chehab break; 128786baecfSMauro Carvalho Chehab case HIERARCHY_4: 129786baecfSMauro Carvalho Chehab tps |= (3 << 10); 130786baecfSMauro Carvalho Chehab break; 131786baecfSMauro Carvalho Chehab case HIERARCHY_NONE: 132786baecfSMauro Carvalho Chehab default: 133786baecfSMauro Carvalho Chehab /* tps |= (0 << 10) */; 134786baecfSMauro Carvalho Chehab } 135786baecfSMauro Carvalho Chehab 136786baecfSMauro Carvalho Chehab return tps; 137786baecfSMauro Carvalho Chehab } 138786baecfSMauro Carvalho Chehab 139786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state { 140786baecfSMauro Carvalho Chehab struct dvb_frontend fe; 141786baecfSMauro Carvalho Chehab struct dvb_usb_device *d; 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 struct dvbt_get_status_msg result; 150786baecfSMauro Carvalho Chehab u8 cmd[] = { CINERGYT2_EP1_GET_TUNER_STATUS }; 151786baecfSMauro Carvalho Chehab int ret; 152786baecfSMauro Carvalho Chehab 153786baecfSMauro Carvalho Chehab ret = dvb_usb_generic_rw(state->d, cmd, sizeof(cmd), (u8 *)&result, 154786baecfSMauro Carvalho Chehab sizeof(result), 0); 155786baecfSMauro Carvalho Chehab if (ret < 0) 156786baecfSMauro Carvalho Chehab return ret; 157786baecfSMauro Carvalho Chehab 158c2730eefSMauro Carvalho Chehab state->status = result; 159c2730eefSMauro Carvalho Chehab 160786baecfSMauro Carvalho Chehab *status = 0; 161786baecfSMauro Carvalho Chehab 162786baecfSMauro Carvalho Chehab if (0xffff - le16_to_cpu(result.gain) > 30) 163786baecfSMauro Carvalho Chehab *status |= FE_HAS_SIGNAL; 164786baecfSMauro Carvalho Chehab if (result.lock_bits & (1 << 6)) 165786baecfSMauro Carvalho Chehab *status |= FE_HAS_LOCK; 166786baecfSMauro Carvalho Chehab if (result.lock_bits & (1 << 5)) 167786baecfSMauro Carvalho Chehab *status |= FE_HAS_SYNC; 168786baecfSMauro Carvalho Chehab if (result.lock_bits & (1 << 4)) 169786baecfSMauro Carvalho Chehab *status |= FE_HAS_CARRIER; 170786baecfSMauro Carvalho Chehab if (result.lock_bits & (1 << 1)) 171786baecfSMauro Carvalho Chehab *status |= FE_HAS_VITERBI; 172786baecfSMauro Carvalho Chehab 173786baecfSMauro Carvalho Chehab if ((*status & (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) != 174786baecfSMauro Carvalho Chehab (FE_HAS_CARRIER | FE_HAS_VITERBI | FE_HAS_SYNC)) 175786baecfSMauro Carvalho Chehab *status &= ~FE_HAS_LOCK; 176786baecfSMauro Carvalho Chehab 177786baecfSMauro Carvalho Chehab return 0; 178786baecfSMauro Carvalho Chehab } 179786baecfSMauro Carvalho Chehab 180786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_ber(struct dvb_frontend *fe, u32 *ber) 181786baecfSMauro Carvalho Chehab { 182786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 183786baecfSMauro Carvalho Chehab 184c2730eefSMauro Carvalho Chehab *ber = le32_to_cpu(state->status.viterbi_error_rate); 185786baecfSMauro Carvalho Chehab return 0; 186786baecfSMauro Carvalho Chehab } 187786baecfSMauro Carvalho Chehab 188786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_unc_blocks(struct dvb_frontend *fe, u32 *unc) 189786baecfSMauro Carvalho Chehab { 190786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 191786baecfSMauro Carvalho Chehab 192c2730eefSMauro Carvalho Chehab *unc = le32_to_cpu(state->status.uncorrected_block_count); 193786baecfSMauro Carvalho Chehab return 0; 194786baecfSMauro Carvalho Chehab } 195786baecfSMauro Carvalho Chehab 196786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_signal_strength(struct dvb_frontend *fe, 197786baecfSMauro Carvalho Chehab u16 *strength) 198786baecfSMauro Carvalho Chehab { 199786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 200786baecfSMauro Carvalho Chehab 201c2730eefSMauro Carvalho Chehab *strength = (0xffff - le16_to_cpu(state->status.gain)); 202786baecfSMauro Carvalho Chehab return 0; 203786baecfSMauro Carvalho Chehab } 204786baecfSMauro Carvalho Chehab 205786baecfSMauro Carvalho Chehab static int cinergyt2_fe_read_snr(struct dvb_frontend *fe, u16 *snr) 206786baecfSMauro Carvalho Chehab { 207786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 208786baecfSMauro Carvalho Chehab 209c2730eefSMauro Carvalho Chehab *snr = (state->status.snr << 8) | state->status.snr; 210786baecfSMauro Carvalho Chehab return 0; 211786baecfSMauro Carvalho Chehab } 212786baecfSMauro Carvalho Chehab 213786baecfSMauro Carvalho Chehab static int cinergyt2_fe_init(struct dvb_frontend *fe) 214786baecfSMauro Carvalho Chehab { 215786baecfSMauro Carvalho Chehab return 0; 216786baecfSMauro Carvalho Chehab } 217786baecfSMauro Carvalho Chehab 218786baecfSMauro Carvalho Chehab static int cinergyt2_fe_sleep(struct dvb_frontend *fe) 219786baecfSMauro Carvalho Chehab { 220786baecfSMauro Carvalho Chehab deb_info("cinergyt2_fe_sleep() Called\n"); 221786baecfSMauro Carvalho Chehab return 0; 222786baecfSMauro Carvalho Chehab } 223786baecfSMauro Carvalho Chehab 224786baecfSMauro Carvalho Chehab static int cinergyt2_fe_get_tune_settings(struct dvb_frontend *fe, 225786baecfSMauro Carvalho Chehab struct dvb_frontend_tune_settings *tune) 226786baecfSMauro Carvalho Chehab { 227786baecfSMauro Carvalho Chehab tune->min_delay_ms = 800; 228786baecfSMauro Carvalho Chehab return 0; 229786baecfSMauro Carvalho Chehab } 230786baecfSMauro Carvalho Chehab 231786baecfSMauro Carvalho Chehab static int cinergyt2_fe_set_frontend(struct dvb_frontend *fe) 232786baecfSMauro Carvalho Chehab { 233786baecfSMauro Carvalho Chehab struct dtv_frontend_properties *fep = &fe->dtv_property_cache; 234786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 235786baecfSMauro Carvalho Chehab struct dvbt_set_parameters_msg param; 236786baecfSMauro Carvalho Chehab char result[2]; 237786baecfSMauro Carvalho Chehab int err; 238786baecfSMauro Carvalho Chehab 239786baecfSMauro Carvalho Chehab param.cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; 240786baecfSMauro Carvalho Chehab param.tps = cpu_to_le16(compute_tps(fep)); 241786baecfSMauro Carvalho Chehab param.freq = cpu_to_le32(fep->frequency / 1000); 242786baecfSMauro Carvalho Chehab param.flags = 0; 243786baecfSMauro Carvalho Chehab 244786baecfSMauro Carvalho Chehab switch (fep->bandwidth_hz) { 245786baecfSMauro Carvalho Chehab default: 246786baecfSMauro Carvalho Chehab case 8000000: 247786baecfSMauro Carvalho Chehab param.bandwidth = 8; 248786baecfSMauro Carvalho Chehab break; 249786baecfSMauro Carvalho Chehab case 7000000: 250786baecfSMauro Carvalho Chehab param.bandwidth = 7; 251786baecfSMauro Carvalho Chehab break; 252786baecfSMauro Carvalho Chehab case 6000000: 253786baecfSMauro Carvalho Chehab param.bandwidth = 6; 254786baecfSMauro Carvalho Chehab break; 255786baecfSMauro Carvalho Chehab } 256786baecfSMauro Carvalho Chehab 257786baecfSMauro Carvalho Chehab err = dvb_usb_generic_rw(state->d, 258786baecfSMauro Carvalho Chehab (char *)¶m, sizeof(param), 259786baecfSMauro Carvalho Chehab result, sizeof(result), 0); 260786baecfSMauro Carvalho Chehab if (err < 0) 261786baecfSMauro Carvalho Chehab err("cinergyt2_fe_set_frontend() Failed! err=%d\n", err); 262786baecfSMauro Carvalho Chehab 263786baecfSMauro Carvalho Chehab return (err < 0) ? err : 0; 264786baecfSMauro Carvalho Chehab } 265786baecfSMauro Carvalho Chehab 266786baecfSMauro Carvalho Chehab static void cinergyt2_fe_release(struct dvb_frontend *fe) 267786baecfSMauro Carvalho Chehab { 268786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *state = fe->demodulator_priv; 269786baecfSMauro Carvalho Chehab kfree(state); 270786baecfSMauro Carvalho Chehab } 271786baecfSMauro Carvalho Chehab 272786baecfSMauro Carvalho Chehab static struct dvb_frontend_ops cinergyt2_fe_ops; 273786baecfSMauro Carvalho Chehab 274786baecfSMauro Carvalho Chehab struct dvb_frontend *cinergyt2_fe_attach(struct dvb_usb_device *d) 275786baecfSMauro Carvalho Chehab { 276786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state *s = kzalloc(sizeof( 277786baecfSMauro Carvalho Chehab struct cinergyt2_fe_state), GFP_KERNEL); 278786baecfSMauro Carvalho Chehab if (s == NULL) 279786baecfSMauro Carvalho Chehab return NULL; 280786baecfSMauro Carvalho Chehab 281786baecfSMauro Carvalho Chehab s->d = d; 282786baecfSMauro Carvalho Chehab memcpy(&s->fe.ops, &cinergyt2_fe_ops, sizeof(struct dvb_frontend_ops)); 283786baecfSMauro Carvalho Chehab s->fe.demodulator_priv = s; 284786baecfSMauro Carvalho Chehab return &s->fe; 285786baecfSMauro Carvalho Chehab } 286786baecfSMauro Carvalho Chehab 287786baecfSMauro Carvalho Chehab 288786baecfSMauro Carvalho Chehab static struct dvb_frontend_ops cinergyt2_fe_ops = { 289786baecfSMauro Carvalho Chehab .delsys = { SYS_DVBT }, 290786baecfSMauro Carvalho Chehab .info = { 291786baecfSMauro Carvalho Chehab .name = DRIVER_NAME, 292786baecfSMauro Carvalho Chehab .frequency_min = 174000000, 293786baecfSMauro Carvalho Chehab .frequency_max = 862000000, 294786baecfSMauro Carvalho Chehab .frequency_stepsize = 166667, 295786baecfSMauro Carvalho Chehab .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_1_2 296786baecfSMauro Carvalho Chehab | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 297786baecfSMauro Carvalho Chehab | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 298786baecfSMauro Carvalho Chehab | FE_CAN_FEC_AUTO | FE_CAN_QPSK 299786baecfSMauro Carvalho Chehab | FE_CAN_QAM_16 | FE_CAN_QAM_64 300786baecfSMauro Carvalho Chehab | FE_CAN_QAM_AUTO 301786baecfSMauro Carvalho Chehab | FE_CAN_TRANSMISSION_MODE_AUTO 302786baecfSMauro Carvalho Chehab | FE_CAN_GUARD_INTERVAL_AUTO 303786baecfSMauro Carvalho Chehab | FE_CAN_HIERARCHY_AUTO 304786baecfSMauro Carvalho Chehab | FE_CAN_RECOVER 305786baecfSMauro Carvalho Chehab | FE_CAN_MUTE_TS 306786baecfSMauro Carvalho Chehab }, 307786baecfSMauro Carvalho Chehab 308786baecfSMauro Carvalho Chehab .release = cinergyt2_fe_release, 309786baecfSMauro Carvalho Chehab 310786baecfSMauro Carvalho Chehab .init = cinergyt2_fe_init, 311786baecfSMauro Carvalho Chehab .sleep = cinergyt2_fe_sleep, 312786baecfSMauro Carvalho Chehab 313786baecfSMauro Carvalho Chehab .set_frontend = cinergyt2_fe_set_frontend, 314786baecfSMauro Carvalho Chehab .get_tune_settings = cinergyt2_fe_get_tune_settings, 315786baecfSMauro Carvalho Chehab 316786baecfSMauro Carvalho Chehab .read_status = cinergyt2_fe_read_status, 317786baecfSMauro Carvalho Chehab .read_ber = cinergyt2_fe_read_ber, 318786baecfSMauro Carvalho Chehab .read_signal_strength = cinergyt2_fe_read_signal_strength, 319786baecfSMauro Carvalho Chehab .read_snr = cinergyt2_fe_read_snr, 320786baecfSMauro Carvalho Chehab .read_ucblocks = cinergyt2_fe_read_unc_blocks, 321786baecfSMauro Carvalho Chehab }; 322