1 // SPDX-License-Identifier: GPL-2.0
3 * cxd2880_tnrdmd_dvbt_mon.c
4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5 * DVB-T monitor functions
7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
10 #include "cxd2880_tnrdmd_mon.h"
11 #include "cxd2880_tnrdmd_dvbt.h"
12 #include "cxd2880_tnrdmd_dvbt_mon.h"
14 #include <media/dvb_math.h>
16 static const int ref_dbm_1000
[3][5] = {
17 {-93000, -91000, -90000, -89000, -88000},
18 {-87000, -85000, -84000, -83000, -82000},
19 {-82000, -80000, -78000, -77000, -76000},
22 static int is_tps_locked(struct cxd2880_tnrdmd
*tnr_dmd
);
24 int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
25 *tnr_dmd
, u8
*sync_stat
,
32 if (!tnr_dmd
|| !sync_stat
|| !ts_lock_stat
|| !unlock_detected
)
35 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
37 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
40 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
46 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
52 *unlock_detected
= (rdata
& 0x10) ? 1 : 0;
53 *sync_stat
= rdata
& 0x07;
54 *ts_lock_stat
= (rdata
& 0x20) ? 1 : 0;
56 if (*sync_stat
== 0x07)
62 int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
63 *tnr_dmd
, u8
*sync_stat
,
68 if (!tnr_dmd
|| !sync_stat
|| !unlock_detected
)
71 if (tnr_dmd
->diver_mode
!= CXD2880_TNRDMD_DIVERMODE_MAIN
)
74 return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd
->diver_sub
,
80 int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
82 enum cxd2880_dvbt_mode
84 enum cxd2880_dvbt_guard
90 if (!tnr_dmd
|| !mode
|| !guard
)
93 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
96 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
99 ret
= slvt_freeze_reg(tnr_dmd
);
103 ret
= is_tps_locked(tnr_dmd
);
105 slvt_unfreeze_reg(tnr_dmd
);
107 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_MAIN
)
109 cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd
->diver_sub
,
115 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
119 slvt_unfreeze_reg(tnr_dmd
);
123 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
127 slvt_unfreeze_reg(tnr_dmd
);
131 slvt_unfreeze_reg(tnr_dmd
);
133 *mode
= (enum cxd2880_dvbt_mode
)((rdata
>> 2) & 0x03);
134 *guard
= (enum cxd2880_dvbt_guard
)(rdata
& 0x03);
139 int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
140 *tnr_dmd
, int *offset
)
146 if (!tnr_dmd
|| !offset
)
149 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
152 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
155 ret
= slvt_freeze_reg(tnr_dmd
);
159 ret
= is_tps_locked(tnr_dmd
);
161 slvt_unfreeze_reg(tnr_dmd
);
165 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
169 slvt_unfreeze_reg(tnr_dmd
);
173 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
177 slvt_unfreeze_reg(tnr_dmd
);
181 slvt_unfreeze_reg(tnr_dmd
);
184 ((rdata
[0] & 0x1f) << 24) | (rdata
[1] << 16) | (rdata
[2] << 8) |
186 *offset
= cxd2880_convert2s_complement(ctl_val
, 29);
187 *offset
= -1 * ((*offset
) * tnr_dmd
->bandwidth
/ 235);
192 int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
197 if (!tnr_dmd
|| !offset
)
200 if (tnr_dmd
->diver_mode
!= CXD2880_TNRDMD_DIVERMODE_MAIN
)
203 return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd
->diver_sub
,
207 int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
209 struct cxd2880_dvbt_tpsinfo
216 if (!tnr_dmd
|| !info
)
219 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
222 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
225 ret
= slvt_freeze_reg(tnr_dmd
);
229 ret
= is_tps_locked(tnr_dmd
);
231 slvt_unfreeze_reg(tnr_dmd
);
233 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_MAIN
)
235 cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd
->diver_sub
,
241 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
245 slvt_unfreeze_reg(tnr_dmd
);
249 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
253 slvt_unfreeze_reg(tnr_dmd
);
257 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
261 slvt_unfreeze_reg(tnr_dmd
);
265 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
267 0xd5, &cell_id_ok
, 1);
269 slvt_unfreeze_reg(tnr_dmd
);
273 slvt_unfreeze_reg(tnr_dmd
);
275 info
->constellation
=
276 (enum cxd2880_dvbt_constellation
)((rdata
[0] >> 6) & 0x03);
277 info
->hierarchy
= (enum cxd2880_dvbt_hierarchy
)((rdata
[0] >> 3) & 0x07);
278 info
->rate_hp
= (enum cxd2880_dvbt_coderate
)(rdata
[0] & 0x07);
279 info
->rate_lp
= (enum cxd2880_dvbt_coderate
)((rdata
[1] >> 5) & 0x07);
280 info
->guard
= (enum cxd2880_dvbt_guard
)((rdata
[1] >> 3) & 0x03);
281 info
->mode
= (enum cxd2880_dvbt_mode
)((rdata
[1] >> 1) & 0x03);
282 info
->fnum
= (rdata
[2] >> 6) & 0x03;
283 info
->length_indicator
= rdata
[2] & 0x3f;
284 info
->cell_id
= (rdata
[3] << 8) | rdata
[4];
285 info
->reserved_even
= rdata
[5] & 0x3f;
286 info
->reserved_odd
= rdata
[6] & 0x3f;
288 info
->cell_id_ok
= cell_id_ok
& 0x01;
293 int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
301 if (!tnr_dmd
|| !pen
)
304 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_SUB
)
307 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
310 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
313 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
319 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
325 if (!(rdata
[0] & 0x01))
328 *pen
= (rdata
[1] << 8) | rdata
[2];
333 int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
336 cxd2880_tnrdmd_spectrum_sense
342 if (!tnr_dmd
|| !sense
)
345 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
348 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
351 ret
= slvt_freeze_reg(tnr_dmd
);
355 ret
= is_tps_locked(tnr_dmd
);
357 slvt_unfreeze_reg(tnr_dmd
);
359 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_MAIN
)
360 ret
= cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd
->diver_sub
,
366 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
370 slvt_unfreeze_reg(tnr_dmd
);
374 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
376 0x1c, &data
, sizeof(data
));
378 slvt_unfreeze_reg(tnr_dmd
);
382 slvt_unfreeze_reg(tnr_dmd
);
385 (data
& 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV
:
386 CXD2880_TNRDMD_SPECTRUM_NORMAL
;
391 static int dvbt_read_snr_reg(struct cxd2880_tnrdmd
*tnr_dmd
,
397 if (!tnr_dmd
|| !reg_value
)
400 ret
= slvt_freeze_reg(tnr_dmd
);
404 ret
= is_tps_locked(tnr_dmd
);
406 slvt_unfreeze_reg(tnr_dmd
);
410 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
414 slvt_unfreeze_reg(tnr_dmd
);
418 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
422 slvt_unfreeze_reg(tnr_dmd
);
426 slvt_unfreeze_reg(tnr_dmd
);
428 *reg_value
= (rdata
[0] << 8) | rdata
[1];
433 static int dvbt_calc_snr(struct cxd2880_tnrdmd
*tnr_dmd
,
434 u32 reg_value
, int *snr
)
436 if (!tnr_dmd
|| !snr
)
442 if (reg_value
> 4996)
445 *snr
= intlog10(reg_value
) - intlog10(5350 - reg_value
);
446 *snr
= (*snr
+ 839) / 1678 + 28500;
451 int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd
*tnr_dmd
,
457 if (!tnr_dmd
|| !snr
)
462 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_SUB
)
465 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
468 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
471 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_SINGLE
) {
472 ret
= dvbt_read_snr_reg(tnr_dmd
, ®_value
);
476 ret
= dvbt_calc_snr(tnr_dmd
, reg_value
, snr
);
482 cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd
, snr
, &snr_main
,
489 int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
491 int *snr_main
, int *snr_sub
)
494 u32 reg_value_sum
= 0;
497 if (!tnr_dmd
|| !snr
|| !snr_main
|| !snr_sub
)
501 *snr_main
= -1000 * 1000;
502 *snr_sub
= -1000 * 1000;
504 if (tnr_dmd
->diver_mode
!= CXD2880_TNRDMD_DIVERMODE_MAIN
)
507 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
510 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
513 ret
= dvbt_read_snr_reg(tnr_dmd
, ®_value
);
515 ret
= dvbt_calc_snr(tnr_dmd
, reg_value
, snr_main
);
518 } else if (ret
== -EAGAIN
) {
524 reg_value_sum
+= reg_value
;
526 ret
= dvbt_read_snr_reg(tnr_dmd
->diver_sub
, ®_value
);
528 ret
= dvbt_calc_snr(tnr_dmd
->diver_sub
, reg_value
, snr_sub
);
531 } else if (ret
== -EAGAIN
) {
537 reg_value_sum
+= reg_value
;
539 return dvbt_calc_snr(tnr_dmd
, reg_value_sum
, snr
);
542 int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
546 u8 nominal_rate_reg
[5];
548 u32 trcg_nominal_rate
= 0;
554 if (!tnr_dmd
|| !ppm
)
557 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
560 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
563 ret
= slvt_freeze_reg(tnr_dmd
);
567 ret
= is_tps_locked(tnr_dmd
);
569 slvt_unfreeze_reg(tnr_dmd
);
573 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
577 slvt_unfreeze_reg(tnr_dmd
);
581 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
584 sizeof(ctl_val_reg
));
586 slvt_unfreeze_reg(tnr_dmd
);
590 ret
= tnr_dmd
->io
->write_reg(tnr_dmd
->io
,
594 slvt_unfreeze_reg(tnr_dmd
);
598 ret
= tnr_dmd
->io
->read_regs(tnr_dmd
->io
,
600 0x60, nominal_rate_reg
,
601 sizeof(nominal_rate_reg
));
603 slvt_unfreeze_reg(tnr_dmd
);
607 slvt_unfreeze_reg(tnr_dmd
);
610 (ctl_val_reg
[0] & 0x7f) - (nominal_rate_reg
[0] & 0x7f);
612 if (diff_upper
< -1 || diff_upper
> 1)
615 trl_ctl_val
= ctl_val_reg
[1] << 24;
616 trl_ctl_val
|= ctl_val_reg
[2] << 16;
617 trl_ctl_val
|= ctl_val_reg
[3] << 8;
618 trl_ctl_val
|= ctl_val_reg
[4];
620 trcg_nominal_rate
= nominal_rate_reg
[1] << 24;
621 trcg_nominal_rate
|= nominal_rate_reg
[2] << 16;
622 trcg_nominal_rate
|= nominal_rate_reg
[3] << 8;
623 trcg_nominal_rate
|= nominal_rate_reg
[4];
626 trcg_nominal_rate
>>= 1;
630 (int)((trl_ctl_val
+ 0x80000000u
) -
632 else if (diff_upper
== -1)
634 -(int)((trcg_nominal_rate
+ 0x80000000u
) -
637 num
= (int)(trl_ctl_val
- trcg_nominal_rate
);
639 den
= (nominal_rate_reg
[0] & 0x7f) << 24;
640 den
|= nominal_rate_reg
[1] << 16;
641 den
|= nominal_rate_reg
[2] << 8;
642 den
|= nominal_rate_reg
[3];
643 den
= (den
+ (390625 / 2)) / 390625;
648 *ppm
= (num
+ (den
/ 2)) / den
;
650 *ppm
= (num
- (den
/ 2)) / den
;
655 int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
659 if (!tnr_dmd
|| !ppm
)
662 if (tnr_dmd
->diver_mode
!= CXD2880_TNRDMD_DIVERMODE_MAIN
)
665 return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd
->diver_sub
, ppm
);
668 static int dvbt_calc_ssi(struct cxd2880_tnrdmd
*tnr_dmd
,
671 struct cxd2880_dvbt_tpsinfo tps
;
676 if (!tnr_dmd
|| !ssi
)
679 ret
= cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd
, &tps
);
683 if (tps
.constellation
>= CXD2880_DVBT_CONSTELLATION_RESERVED_3
||
684 tps
.rate_hp
>= CXD2880_DVBT_CODERATE_RESERVED_5
)
687 prel
= rf_lvl
- ref_dbm_1000
[tps
.constellation
][tps
.rate_hp
];
692 temp_ssi
= ((2 * (prel
+ 15000)) + 1500) / 3000;
693 else if (prel
< 20000)
694 temp_ssi
= (((4 * prel
) + 500) / 1000) + 10;
695 else if (prel
< 35000)
696 temp_ssi
= (((2 * (prel
- 20000)) + 1500) / 3000) + 90;
700 *ssi
= (temp_ssi
> 100) ? 100 : (u8
)temp_ssi
;
705 int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd
*tnr_dmd
,
711 if (!tnr_dmd
|| !ssi
)
714 if (tnr_dmd
->diver_mode
== CXD2880_TNRDMD_DIVERMODE_SUB
)
717 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
720 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
723 ret
= cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd
, &rf_lvl
);
727 return dvbt_calc_ssi(tnr_dmd
, rf_lvl
, ssi
);
730 int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd
*tnr_dmd
,
736 if (!tnr_dmd
|| !ssi
)
739 if (tnr_dmd
->diver_mode
!= CXD2880_TNRDMD_DIVERMODE_MAIN
)
742 if (tnr_dmd
->state
!= CXD2880_TNRDMD_STATE_ACTIVE
)
745 if (tnr_dmd
->sys
!= CXD2880_DTV_SYS_DVBT
)
748 ret
= cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd
->diver_sub
, &rf_lvl
);
752 return dvbt_calc_ssi(tnr_dmd
, rf_lvl
, ssi
);
755 static int is_tps_locked(struct cxd2880_tnrdmd
*tnr_dmd
)
766 cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd
, &sync
, &tslock
,