1 /* 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> 5 * 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) 9 * any later version. 10 * 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. 15 */ 16 17 #include <media/dvb_frontend.h> 18 19 #include "as102_fe.h" 20 21 struct as102_state { 22 struct dvb_frontend frontend; 23 struct as10x_demod_stats demod_stats; 24 25 const struct as102_fe_ops *ops; 26 void *priv; 27 uint8_t elna_cfg; 28 29 /* signal strength */ 30 uint16_t signal_strength; 31 /* bit error rate */ 32 uint32_t ber; 33 }; 34 35 static uint8_t as102_fe_get_code_rate(enum fe_code_rate arg) 36 { 37 uint8_t c; 38 39 switch (arg) { 40 case FEC_1_2: 41 c = CODE_RATE_1_2; 42 break; 43 case FEC_2_3: 44 c = CODE_RATE_2_3; 45 break; 46 case FEC_3_4: 47 c = CODE_RATE_3_4; 48 break; 49 case FEC_5_6: 50 c = CODE_RATE_5_6; 51 break; 52 case FEC_7_8: 53 c = CODE_RATE_7_8; 54 break; 55 default: 56 c = CODE_RATE_UNKNOWN; 57 break; 58 } 59 60 return c; 61 } 62 63 static int as102_fe_set_frontend(struct dvb_frontend *fe) 64 { 65 struct as102_state *state = fe->demodulator_priv; 66 struct dtv_frontend_properties *c = &fe->dtv_property_cache; 67 struct as10x_tune_args tune_args = { 0 }; 68 69 /* set frequency */ 70 tune_args.freq = c->frequency / 1000; 71 72 /* fix interleaving_mode */ 73 tune_args.interleaving_mode = INTLV_NATIVE; 74 75 switch (c->bandwidth_hz) { 76 case 8000000: 77 tune_args.bandwidth = BW_8_MHZ; 78 break; 79 case 7000000: 80 tune_args.bandwidth = BW_7_MHZ; 81 break; 82 case 6000000: 83 tune_args.bandwidth = BW_6_MHZ; 84 break; 85 default: 86 tune_args.bandwidth = BW_8_MHZ; 87 } 88 89 switch (c->guard_interval) { 90 case GUARD_INTERVAL_1_32: 91 tune_args.guard_interval = GUARD_INT_1_32; 92 break; 93 case GUARD_INTERVAL_1_16: 94 tune_args.guard_interval = GUARD_INT_1_16; 95 break; 96 case GUARD_INTERVAL_1_8: 97 tune_args.guard_interval = GUARD_INT_1_8; 98 break; 99 case GUARD_INTERVAL_1_4: 100 tune_args.guard_interval = GUARD_INT_1_4; 101 break; 102 case GUARD_INTERVAL_AUTO: 103 default: 104 tune_args.guard_interval = GUARD_UNKNOWN; 105 break; 106 } 107 108 switch (c->modulation) { 109 case QPSK: 110 tune_args.modulation = CONST_QPSK; 111 break; 112 case QAM_16: 113 tune_args.modulation = CONST_QAM16; 114 break; 115 case QAM_64: 116 tune_args.modulation = CONST_QAM64; 117 break; 118 default: 119 tune_args.modulation = CONST_UNKNOWN; 120 break; 121 } 122 123 switch (c->transmission_mode) { 124 case TRANSMISSION_MODE_2K: 125 tune_args.transmission_mode = TRANS_MODE_2K; 126 break; 127 case TRANSMISSION_MODE_8K: 128 tune_args.transmission_mode = TRANS_MODE_8K; 129 break; 130 default: 131 tune_args.transmission_mode = TRANS_MODE_UNKNOWN; 132 } 133 134 switch (c->hierarchy) { 135 case HIERARCHY_NONE: 136 tune_args.hierarchy = HIER_NONE; 137 break; 138 case HIERARCHY_1: 139 tune_args.hierarchy = HIER_ALPHA_1; 140 break; 141 case HIERARCHY_2: 142 tune_args.hierarchy = HIER_ALPHA_2; 143 break; 144 case HIERARCHY_4: 145 tune_args.hierarchy = HIER_ALPHA_4; 146 break; 147 case HIERARCHY_AUTO: 148 tune_args.hierarchy = HIER_UNKNOWN; 149 break; 150 } 151 152 pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n", 153 c->frequency, 154 tune_args.bandwidth, 155 tune_args.guard_interval); 156 157 /* 158 * Detect a hierarchy selection 159 * if HP/LP are both set to FEC_NONE, HP will be selected. 160 */ 161 if ((tune_args.hierarchy != HIER_NONE) && 162 ((c->code_rate_LP == FEC_NONE) || 163 (c->code_rate_HP == FEC_NONE))) { 164 165 if (c->code_rate_LP == FEC_NONE) { 166 tune_args.hier_select = HIER_HIGH_PRIORITY; 167 tune_args.code_rate = 168 as102_fe_get_code_rate(c->code_rate_HP); 169 } 170 171 if (c->code_rate_HP == FEC_NONE) { 172 tune_args.hier_select = HIER_LOW_PRIORITY; 173 tune_args.code_rate = 174 as102_fe_get_code_rate(c->code_rate_LP); 175 } 176 177 pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n", 178 tune_args.hierarchy, 179 tune_args.hier_select == HIER_HIGH_PRIORITY ? 180 "HP" : "LP", 181 tune_args.hier_select == HIER_HIGH_PRIORITY ? 182 "HP" : "LP", 183 tune_args.code_rate); 184 } else { 185 tune_args.code_rate = 186 as102_fe_get_code_rate(c->code_rate_HP); 187 } 188 189 /* Set frontend arguments */ 190 return state->ops->set_tune(state->priv, &tune_args); 191 } 192 193 static int as102_fe_get_frontend(struct dvb_frontend *fe, 194 struct dtv_frontend_properties *c) 195 { 196 struct as102_state *state = fe->demodulator_priv; 197 int ret = 0; 198 struct as10x_tps tps = { 0 }; 199 200 /* send abilis command: GET_TPS */ 201 ret = state->ops->get_tps(state->priv, &tps); 202 if (ret < 0) 203 return ret; 204 205 /* extract constellation */ 206 switch (tps.modulation) { 207 case CONST_QPSK: 208 c->modulation = QPSK; 209 break; 210 case CONST_QAM16: 211 c->modulation = QAM_16; 212 break; 213 case CONST_QAM64: 214 c->modulation = QAM_64; 215 break; 216 } 217 218 /* extract hierarchy */ 219 switch (tps.hierarchy) { 220 case HIER_NONE: 221 c->hierarchy = HIERARCHY_NONE; 222 break; 223 case HIER_ALPHA_1: 224 c->hierarchy = HIERARCHY_1; 225 break; 226 case HIER_ALPHA_2: 227 c->hierarchy = HIERARCHY_2; 228 break; 229 case HIER_ALPHA_4: 230 c->hierarchy = HIERARCHY_4; 231 break; 232 } 233 234 /* extract code rate HP */ 235 switch (tps.code_rate_HP) { 236 case CODE_RATE_1_2: 237 c->code_rate_HP = FEC_1_2; 238 break; 239 case CODE_RATE_2_3: 240 c->code_rate_HP = FEC_2_3; 241 break; 242 case CODE_RATE_3_4: 243 c->code_rate_HP = FEC_3_4; 244 break; 245 case CODE_RATE_5_6: 246 c->code_rate_HP = FEC_5_6; 247 break; 248 case CODE_RATE_7_8: 249 c->code_rate_HP = FEC_7_8; 250 break; 251 } 252 253 /* extract code rate LP */ 254 switch (tps.code_rate_LP) { 255 case CODE_RATE_1_2: 256 c->code_rate_LP = FEC_1_2; 257 break; 258 case CODE_RATE_2_3: 259 c->code_rate_LP = FEC_2_3; 260 break; 261 case CODE_RATE_3_4: 262 c->code_rate_LP = FEC_3_4; 263 break; 264 case CODE_RATE_5_6: 265 c->code_rate_LP = FEC_5_6; 266 break; 267 case CODE_RATE_7_8: 268 c->code_rate_LP = FEC_7_8; 269 break; 270 } 271 272 /* extract guard interval */ 273 switch (tps.guard_interval) { 274 case GUARD_INT_1_32: 275 c->guard_interval = GUARD_INTERVAL_1_32; 276 break; 277 case GUARD_INT_1_16: 278 c->guard_interval = GUARD_INTERVAL_1_16; 279 break; 280 case GUARD_INT_1_8: 281 c->guard_interval = GUARD_INTERVAL_1_8; 282 break; 283 case GUARD_INT_1_4: 284 c->guard_interval = GUARD_INTERVAL_1_4; 285 break; 286 } 287 288 /* extract transmission mode */ 289 switch (tps.transmission_mode) { 290 case TRANS_MODE_2K: 291 c->transmission_mode = TRANSMISSION_MODE_2K; 292 break; 293 case TRANS_MODE_8K: 294 c->transmission_mode = TRANSMISSION_MODE_8K; 295 break; 296 } 297 298 return 0; 299 } 300 301 static int as102_fe_get_tune_settings(struct dvb_frontend *fe, 302 struct dvb_frontend_tune_settings *settings) { 303 304 settings->min_delay_ms = 1000; 305 306 return 0; 307 } 308 309 static int as102_fe_read_status(struct dvb_frontend *fe, enum fe_status *status) 310 { 311 int ret = 0; 312 struct as102_state *state = fe->demodulator_priv; 313 struct as10x_tune_status tstate = { 0 }; 314 315 /* send abilis command: GET_TUNE_STATUS */ 316 ret = state->ops->get_status(state->priv, &tstate); 317 if (ret < 0) 318 return ret; 319 320 state->signal_strength = tstate.signal_strength; 321 state->ber = tstate.BER; 322 323 switch (tstate.tune_state) { 324 case TUNE_STATUS_SIGNAL_DVB_OK: 325 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER; 326 break; 327 case TUNE_STATUS_STREAM_DETECTED: 328 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | 329 FE_HAS_VITERBI; 330 break; 331 case TUNE_STATUS_STREAM_TUNED: 332 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | 333 FE_HAS_LOCK | FE_HAS_VITERBI; 334 break; 335 default: 336 *status = TUNE_STATUS_NOT_TUNED; 337 } 338 339 pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n", 340 tstate.tune_state, tstate.signal_strength, 341 tstate.PER, tstate.BER); 342 343 if (!(*status & FE_HAS_LOCK)) { 344 memset(&state->demod_stats, 0, sizeof(state->demod_stats)); 345 return 0; 346 } 347 348 ret = state->ops->get_stats(state->priv, &state->demod_stats); 349 if (ret < 0) 350 memset(&state->demod_stats, 0, sizeof(state->demod_stats)); 351 352 return ret; 353 } 354 355 /* 356 * Note: 357 * - in AS102 SNR=MER 358 * - the SNR will be returned in linear terms, i.e. not in dB 359 * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB 360 * - the accuracy is >2dB for SNR values outside this range 361 */ 362 static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr) 363 { 364 struct as102_state *state = fe->demodulator_priv; 365 366 *snr = state->demod_stats.mer; 367 368 return 0; 369 } 370 371 static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber) 372 { 373 struct as102_state *state = fe->demodulator_priv; 374 375 *ber = state->ber; 376 377 return 0; 378 } 379 380 static int as102_fe_read_signal_strength(struct dvb_frontend *fe, 381 u16 *strength) 382 { 383 struct as102_state *state = fe->demodulator_priv; 384 385 *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2); 386 387 return 0; 388 } 389 390 static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) 391 { 392 struct as102_state *state = fe->demodulator_priv; 393 394 if (state->demod_stats.has_started) 395 *ucblocks = state->demod_stats.bad_frame_count; 396 else 397 *ucblocks = 0; 398 399 return 0; 400 } 401 402 static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire) 403 { 404 struct as102_state *state = fe->demodulator_priv; 405 406 return state->ops->stream_ctrl(state->priv, acquire, 407 state->elna_cfg); 408 } 409 410 static void as102_fe_release(struct dvb_frontend *fe) 411 { 412 struct as102_state *state = fe->demodulator_priv; 413 414 kfree(state); 415 } 416 417 418 static const struct dvb_frontend_ops as102_fe_ops = { 419 .delsys = { SYS_DVBT }, 420 .info = { 421 .name = "Abilis AS102 DVB-T", 422 .frequency_min_hz = 174 * MHz, 423 .frequency_max_hz = 862 * MHz, 424 .frequency_stepsize_hz = 166667, 425 .caps = FE_CAN_INVERSION_AUTO 426 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 427 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO 428 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK 429 | FE_CAN_QAM_AUTO 430 | FE_CAN_TRANSMISSION_MODE_AUTO 431 | FE_CAN_GUARD_INTERVAL_AUTO 432 | FE_CAN_HIERARCHY_AUTO 433 | FE_CAN_RECOVER 434 | FE_CAN_MUTE_TS 435 }, 436 437 .set_frontend = as102_fe_set_frontend, 438 .get_frontend = as102_fe_get_frontend, 439 .get_tune_settings = as102_fe_get_tune_settings, 440 441 .read_status = as102_fe_read_status, 442 .read_snr = as102_fe_read_snr, 443 .read_ber = as102_fe_read_ber, 444 .read_signal_strength = as102_fe_read_signal_strength, 445 .read_ucblocks = as102_fe_read_ucblocks, 446 .ts_bus_ctrl = as102_fe_ts_bus_ctrl, 447 .release = as102_fe_release, 448 }; 449 450 struct dvb_frontend *as102_attach(const char *name, 451 const struct as102_fe_ops *ops, 452 void *priv, 453 uint8_t elna_cfg) 454 { 455 struct as102_state *state; 456 struct dvb_frontend *fe; 457 458 state = kzalloc(sizeof(*state), GFP_KERNEL); 459 if (!state) 460 return NULL; 461 462 fe = &state->frontend; 463 fe->demodulator_priv = state; 464 state->ops = ops; 465 state->priv = priv; 466 state->elna_cfg = elna_cfg; 467 468 /* init frontend callback ops */ 469 memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops)); 470 strncpy(fe->ops.info.name, name, sizeof(fe->ops.info.name)); 471 472 return fe; 473 474 } 475 EXPORT_SYMBOL_GPL(as102_attach); 476 477 MODULE_DESCRIPTION("as102-fe"); 478 MODULE_LICENSE("GPL"); 479 MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>"); 480