0001
0002
0003
0004
0005
0006
0007
0008 #include <media/dvb_frontend.h>
0009
0010 #include "as102_fe.h"
0011
0012 struct as102_state {
0013 struct dvb_frontend frontend;
0014 struct as10x_demod_stats demod_stats;
0015
0016 const struct as102_fe_ops *ops;
0017 void *priv;
0018 uint8_t elna_cfg;
0019
0020
0021 uint16_t signal_strength;
0022
0023 uint32_t ber;
0024 };
0025
0026 static uint8_t as102_fe_get_code_rate(enum fe_code_rate arg)
0027 {
0028 uint8_t c;
0029
0030 switch (arg) {
0031 case FEC_1_2:
0032 c = CODE_RATE_1_2;
0033 break;
0034 case FEC_2_3:
0035 c = CODE_RATE_2_3;
0036 break;
0037 case FEC_3_4:
0038 c = CODE_RATE_3_4;
0039 break;
0040 case FEC_5_6:
0041 c = CODE_RATE_5_6;
0042 break;
0043 case FEC_7_8:
0044 c = CODE_RATE_7_8;
0045 break;
0046 default:
0047 c = CODE_RATE_UNKNOWN;
0048 break;
0049 }
0050
0051 return c;
0052 }
0053
0054 static int as102_fe_set_frontend(struct dvb_frontend *fe)
0055 {
0056 struct as102_state *state = fe->demodulator_priv;
0057 struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0058 struct as10x_tune_args tune_args = { 0 };
0059
0060
0061 tune_args.freq = c->frequency / 1000;
0062
0063
0064 tune_args.interleaving_mode = INTLV_NATIVE;
0065
0066 switch (c->bandwidth_hz) {
0067 case 8000000:
0068 tune_args.bandwidth = BW_8_MHZ;
0069 break;
0070 case 7000000:
0071 tune_args.bandwidth = BW_7_MHZ;
0072 break;
0073 case 6000000:
0074 tune_args.bandwidth = BW_6_MHZ;
0075 break;
0076 default:
0077 tune_args.bandwidth = BW_8_MHZ;
0078 }
0079
0080 switch (c->guard_interval) {
0081 case GUARD_INTERVAL_1_32:
0082 tune_args.guard_interval = GUARD_INT_1_32;
0083 break;
0084 case GUARD_INTERVAL_1_16:
0085 tune_args.guard_interval = GUARD_INT_1_16;
0086 break;
0087 case GUARD_INTERVAL_1_8:
0088 tune_args.guard_interval = GUARD_INT_1_8;
0089 break;
0090 case GUARD_INTERVAL_1_4:
0091 tune_args.guard_interval = GUARD_INT_1_4;
0092 break;
0093 case GUARD_INTERVAL_AUTO:
0094 default:
0095 tune_args.guard_interval = GUARD_UNKNOWN;
0096 break;
0097 }
0098
0099 switch (c->modulation) {
0100 case QPSK:
0101 tune_args.modulation = CONST_QPSK;
0102 break;
0103 case QAM_16:
0104 tune_args.modulation = CONST_QAM16;
0105 break;
0106 case QAM_64:
0107 tune_args.modulation = CONST_QAM64;
0108 break;
0109 default:
0110 tune_args.modulation = CONST_UNKNOWN;
0111 break;
0112 }
0113
0114 switch (c->transmission_mode) {
0115 case TRANSMISSION_MODE_2K:
0116 tune_args.transmission_mode = TRANS_MODE_2K;
0117 break;
0118 case TRANSMISSION_MODE_8K:
0119 tune_args.transmission_mode = TRANS_MODE_8K;
0120 break;
0121 default:
0122 tune_args.transmission_mode = TRANS_MODE_UNKNOWN;
0123 }
0124
0125 switch (c->hierarchy) {
0126 case HIERARCHY_NONE:
0127 tune_args.hierarchy = HIER_NONE;
0128 break;
0129 case HIERARCHY_1:
0130 tune_args.hierarchy = HIER_ALPHA_1;
0131 break;
0132 case HIERARCHY_2:
0133 tune_args.hierarchy = HIER_ALPHA_2;
0134 break;
0135 case HIERARCHY_4:
0136 tune_args.hierarchy = HIER_ALPHA_4;
0137 break;
0138 case HIERARCHY_AUTO:
0139 tune_args.hierarchy = HIER_UNKNOWN;
0140 break;
0141 }
0142
0143 pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n",
0144 c->frequency,
0145 tune_args.bandwidth,
0146 tune_args.guard_interval);
0147
0148
0149
0150
0151
0152 if ((tune_args.hierarchy != HIER_NONE) &&
0153 ((c->code_rate_LP == FEC_NONE) ||
0154 (c->code_rate_HP == FEC_NONE))) {
0155
0156 if (c->code_rate_LP == FEC_NONE) {
0157 tune_args.hier_select = HIER_HIGH_PRIORITY;
0158 tune_args.code_rate =
0159 as102_fe_get_code_rate(c->code_rate_HP);
0160 }
0161
0162 if (c->code_rate_HP == FEC_NONE) {
0163 tune_args.hier_select = HIER_LOW_PRIORITY;
0164 tune_args.code_rate =
0165 as102_fe_get_code_rate(c->code_rate_LP);
0166 }
0167
0168 pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n",
0169 tune_args.hierarchy,
0170 tune_args.hier_select == HIER_HIGH_PRIORITY ?
0171 "HP" : "LP",
0172 tune_args.hier_select == HIER_HIGH_PRIORITY ?
0173 "HP" : "LP",
0174 tune_args.code_rate);
0175 } else {
0176 tune_args.code_rate =
0177 as102_fe_get_code_rate(c->code_rate_HP);
0178 }
0179
0180
0181 return state->ops->set_tune(state->priv, &tune_args);
0182 }
0183
0184 static int as102_fe_get_frontend(struct dvb_frontend *fe,
0185 struct dtv_frontend_properties *c)
0186 {
0187 struct as102_state *state = fe->demodulator_priv;
0188 int ret = 0;
0189 struct as10x_tps tps = { 0 };
0190
0191
0192 ret = state->ops->get_tps(state->priv, &tps);
0193 if (ret < 0)
0194 return ret;
0195
0196
0197 switch (tps.modulation) {
0198 case CONST_QPSK:
0199 c->modulation = QPSK;
0200 break;
0201 case CONST_QAM16:
0202 c->modulation = QAM_16;
0203 break;
0204 case CONST_QAM64:
0205 c->modulation = QAM_64;
0206 break;
0207 }
0208
0209
0210 switch (tps.hierarchy) {
0211 case HIER_NONE:
0212 c->hierarchy = HIERARCHY_NONE;
0213 break;
0214 case HIER_ALPHA_1:
0215 c->hierarchy = HIERARCHY_1;
0216 break;
0217 case HIER_ALPHA_2:
0218 c->hierarchy = HIERARCHY_2;
0219 break;
0220 case HIER_ALPHA_4:
0221 c->hierarchy = HIERARCHY_4;
0222 break;
0223 }
0224
0225
0226 switch (tps.code_rate_HP) {
0227 case CODE_RATE_1_2:
0228 c->code_rate_HP = FEC_1_2;
0229 break;
0230 case CODE_RATE_2_3:
0231 c->code_rate_HP = FEC_2_3;
0232 break;
0233 case CODE_RATE_3_4:
0234 c->code_rate_HP = FEC_3_4;
0235 break;
0236 case CODE_RATE_5_6:
0237 c->code_rate_HP = FEC_5_6;
0238 break;
0239 case CODE_RATE_7_8:
0240 c->code_rate_HP = FEC_7_8;
0241 break;
0242 }
0243
0244
0245 switch (tps.code_rate_LP) {
0246 case CODE_RATE_1_2:
0247 c->code_rate_LP = FEC_1_2;
0248 break;
0249 case CODE_RATE_2_3:
0250 c->code_rate_LP = FEC_2_3;
0251 break;
0252 case CODE_RATE_3_4:
0253 c->code_rate_LP = FEC_3_4;
0254 break;
0255 case CODE_RATE_5_6:
0256 c->code_rate_LP = FEC_5_6;
0257 break;
0258 case CODE_RATE_7_8:
0259 c->code_rate_LP = FEC_7_8;
0260 break;
0261 }
0262
0263
0264 switch (tps.guard_interval) {
0265 case GUARD_INT_1_32:
0266 c->guard_interval = GUARD_INTERVAL_1_32;
0267 break;
0268 case GUARD_INT_1_16:
0269 c->guard_interval = GUARD_INTERVAL_1_16;
0270 break;
0271 case GUARD_INT_1_8:
0272 c->guard_interval = GUARD_INTERVAL_1_8;
0273 break;
0274 case GUARD_INT_1_4:
0275 c->guard_interval = GUARD_INTERVAL_1_4;
0276 break;
0277 }
0278
0279
0280 switch (tps.transmission_mode) {
0281 case TRANS_MODE_2K:
0282 c->transmission_mode = TRANSMISSION_MODE_2K;
0283 break;
0284 case TRANS_MODE_8K:
0285 c->transmission_mode = TRANSMISSION_MODE_8K;
0286 break;
0287 }
0288
0289 return 0;
0290 }
0291
0292 static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
0293 struct dvb_frontend_tune_settings *settings)
0294 {
0295
0296 settings->min_delay_ms = 1000;
0297
0298 return 0;
0299 }
0300
0301 static int as102_fe_read_status(struct dvb_frontend *fe, enum fe_status *status)
0302 {
0303 int ret = 0;
0304 struct as102_state *state = fe->demodulator_priv;
0305 struct as10x_tune_status tstate = { 0 };
0306
0307
0308 ret = state->ops->get_status(state->priv, &tstate);
0309 if (ret < 0)
0310 return ret;
0311
0312 state->signal_strength = tstate.signal_strength;
0313 state->ber = tstate.BER;
0314
0315 switch (tstate.tune_state) {
0316 case TUNE_STATUS_SIGNAL_DVB_OK:
0317 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
0318 break;
0319 case TUNE_STATUS_STREAM_DETECTED:
0320 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
0321 FE_HAS_VITERBI;
0322 break;
0323 case TUNE_STATUS_STREAM_TUNED:
0324 *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
0325 FE_HAS_LOCK | FE_HAS_VITERBI;
0326 break;
0327 default:
0328 *status = TUNE_STATUS_NOT_TUNED;
0329 }
0330
0331 pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
0332 tstate.tune_state, tstate.signal_strength,
0333 tstate.PER, tstate.BER);
0334
0335 if (!(*status & FE_HAS_LOCK)) {
0336 memset(&state->demod_stats, 0, sizeof(state->demod_stats));
0337 return 0;
0338 }
0339
0340 ret = state->ops->get_stats(state->priv, &state->demod_stats);
0341 if (ret < 0)
0342 memset(&state->demod_stats, 0, sizeof(state->demod_stats));
0343
0344 return ret;
0345 }
0346
0347
0348
0349
0350
0351
0352
0353
0354 static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
0355 {
0356 struct as102_state *state = fe->demodulator_priv;
0357
0358 *snr = state->demod_stats.mer;
0359
0360 return 0;
0361 }
0362
0363 static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
0364 {
0365 struct as102_state *state = fe->demodulator_priv;
0366
0367 *ber = state->ber;
0368
0369 return 0;
0370 }
0371
0372 static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
0373 u16 *strength)
0374 {
0375 struct as102_state *state = fe->demodulator_priv;
0376
0377 *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2);
0378
0379 return 0;
0380 }
0381
0382 static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
0383 {
0384 struct as102_state *state = fe->demodulator_priv;
0385
0386 if (state->demod_stats.has_started)
0387 *ucblocks = state->demod_stats.bad_frame_count;
0388 else
0389 *ucblocks = 0;
0390
0391 return 0;
0392 }
0393
0394 static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
0395 {
0396 struct as102_state *state = fe->demodulator_priv;
0397
0398 return state->ops->stream_ctrl(state->priv, acquire,
0399 state->elna_cfg);
0400 }
0401
0402 static void as102_fe_release(struct dvb_frontend *fe)
0403 {
0404 struct as102_state *state = fe->demodulator_priv;
0405
0406 kfree(state);
0407 }
0408
0409
0410 static const struct dvb_frontend_ops as102_fe_ops = {
0411 .delsys = { SYS_DVBT },
0412 .info = {
0413 .name = "Abilis AS102 DVB-T",
0414 .frequency_min_hz = 174 * MHz,
0415 .frequency_max_hz = 862 * MHz,
0416 .frequency_stepsize_hz = 166667,
0417 .caps = FE_CAN_INVERSION_AUTO
0418 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
0419 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
0420 | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
0421 | FE_CAN_QAM_AUTO
0422 | FE_CAN_TRANSMISSION_MODE_AUTO
0423 | FE_CAN_GUARD_INTERVAL_AUTO
0424 | FE_CAN_HIERARCHY_AUTO
0425 | FE_CAN_RECOVER
0426 | FE_CAN_MUTE_TS
0427 },
0428
0429 .set_frontend = as102_fe_set_frontend,
0430 .get_frontend = as102_fe_get_frontend,
0431 .get_tune_settings = as102_fe_get_tune_settings,
0432
0433 .read_status = as102_fe_read_status,
0434 .read_snr = as102_fe_read_snr,
0435 .read_ber = as102_fe_read_ber,
0436 .read_signal_strength = as102_fe_read_signal_strength,
0437 .read_ucblocks = as102_fe_read_ucblocks,
0438 .ts_bus_ctrl = as102_fe_ts_bus_ctrl,
0439 .release = as102_fe_release,
0440 };
0441
0442 struct dvb_frontend *as102_attach(const char *name,
0443 const struct as102_fe_ops *ops,
0444 void *priv,
0445 uint8_t elna_cfg)
0446 {
0447 struct as102_state *state;
0448 struct dvb_frontend *fe;
0449
0450 state = kzalloc(sizeof(*state), GFP_KERNEL);
0451 if (!state)
0452 return NULL;
0453
0454 fe = &state->frontend;
0455 fe->demodulator_priv = state;
0456 state->ops = ops;
0457 state->priv = priv;
0458 state->elna_cfg = elna_cfg;
0459
0460
0461 memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
0462 strscpy(fe->ops.info.name, name, sizeof(fe->ops.info.name));
0463
0464 return fe;
0465
0466 }
0467 EXPORT_SYMBOL_GPL(as102_attach);
0468
0469 MODULE_DESCRIPTION("as102-fe");
0470 MODULE_LICENSE("GPL");
0471 MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");