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