xref: /linux/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt2_mon.c (revision 55ec81f7517fad09135f65552cea0a3ee84fff30)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cxd2880_tnrdmd_dvbt2_mon.c
4  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5  * DVB-T2 monitor functions
6  *
7  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8  */
9 
10 #include "cxd2880_tnrdmd_mon.h"
11 #include "cxd2880_tnrdmd_dvbt2.h"
12 #include "cxd2880_tnrdmd_dvbt2_mon.h"
13 
14 #include <linux/int_log.h>
15 
16 static const int ref_dbm_1000[4][8] = {
17 	{-96000, -95000, -94000, -93000, -92000, -92000, -98000, -97000},
18 	{-91000, -89000, -88000, -87000, -86000, -86000, -93000, -92000},
19 	{-86000, -85000, -83000, -82000, -81000, -80000, -89000, -88000},
20 	{-82000, -80000, -78000, -76000, -75000, -74000, -86000, -84000},
21 };
22 
23 int cxd2880_tnrdmd_dvbt2_mon_sync_stat(struct cxd2880_tnrdmd
24 				       *tnr_dmd, u8 *sync_stat,
25 				       u8 *ts_lock_stat,
26 				       u8 *unlock_detected)
27 {
28 	u8 data;
29 	int ret;
30 
31 	if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
32 		return -EINVAL;
33 
34 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
35 		return -EINVAL;
36 
37 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
38 		return -EINVAL;
39 
40 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
41 				     CXD2880_IO_TGT_DMD,
42 				     0x00, 0x0b);
43 	if (ret)
44 		return ret;
45 
46 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
47 				     CXD2880_IO_TGT_DMD,
48 				     0x10, &data, sizeof(data));
49 	if (ret)
50 		return ret;
51 
52 	*sync_stat = data & 0x07;
53 	*ts_lock_stat = ((data & 0x20) ? 1 : 0);
54 	*unlock_detected = ((data & 0x10) ? 1 : 0);
55 
56 	if (*sync_stat == 0x07)
57 		return -EAGAIN;
58 
59 	return 0;
60 }
61 
62 int cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(struct cxd2880_tnrdmd
63 					   *tnr_dmd,
64 					   u8 *sync_stat,
65 					   u8 *unlock_detected)
66 {
67 	u8 ts_lock_stat = 0;
68 
69 	if (!tnr_dmd || !sync_stat || !unlock_detected)
70 		return -EINVAL;
71 
72 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
73 		return -EINVAL;
74 
75 	return cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd->diver_sub,
76 						  sync_stat,
77 						  &ts_lock_stat,
78 						  unlock_detected);
79 }
80 
81 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset(struct cxd2880_tnrdmd
82 					    *tnr_dmd, int *offset)
83 {
84 	u8 data[4];
85 	u32 ctl_val = 0;
86 	u8 sync_state = 0;
87 	u8 ts_lock = 0;
88 	u8 unlock_detected = 0;
89 	int ret;
90 
91 	if (!tnr_dmd || !offset)
92 		return -EINVAL;
93 
94 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
95 		return -EINVAL;
96 
97 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
98 		return -EINVAL;
99 
100 	ret = slvt_freeze_reg(tnr_dmd);
101 	if (ret)
102 		return ret;
103 
104 	ret =
105 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
106 					       &ts_lock,
107 					       &unlock_detected);
108 	if (ret) {
109 		slvt_unfreeze_reg(tnr_dmd);
110 		return ret;
111 	}
112 
113 	if (sync_state != 6) {
114 		slvt_unfreeze_reg(tnr_dmd);
115 		return -EAGAIN;
116 	}
117 
118 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
119 				     CXD2880_IO_TGT_DMD,
120 				     0x00, 0x0b);
121 	if (ret) {
122 		slvt_unfreeze_reg(tnr_dmd);
123 		return ret;
124 	}
125 
126 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
127 				     CXD2880_IO_TGT_DMD,
128 				     0x30, data, sizeof(data));
129 	if (ret) {
130 		slvt_unfreeze_reg(tnr_dmd);
131 		return ret;
132 	}
133 
134 	slvt_unfreeze_reg(tnr_dmd);
135 
136 	ctl_val =
137 	    ((data[0] & 0x0f) << 24) | (data[1] << 16) | (data[2] << 8)
138 	    | (data[3]);
139 	*offset = cxd2880_convert2s_complement(ctl_val, 28);
140 
141 	switch (tnr_dmd->bandwidth) {
142 	case CXD2880_DTV_BW_1_7_MHZ:
143 		*offset = -1 * ((*offset) / 582);
144 		break;
145 	case CXD2880_DTV_BW_5_MHZ:
146 	case CXD2880_DTV_BW_6_MHZ:
147 	case CXD2880_DTV_BW_7_MHZ:
148 	case CXD2880_DTV_BW_8_MHZ:
149 		*offset = -1 * ((*offset) * tnr_dmd->bandwidth / 940);
150 		break;
151 	default:
152 		return -EINVAL;
153 	}
154 
155 	return 0;
156 }
157 
158 int cxd2880_tnrdmd_dvbt2_mon_carrier_offset_sub(struct
159 						cxd2880_tnrdmd
160 						*tnr_dmd,
161 						int *offset)
162 {
163 	if (!tnr_dmd || !offset)
164 		return -EINVAL;
165 
166 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
167 		return -EINVAL;
168 
169 	return cxd2880_tnrdmd_dvbt2_mon_carrier_offset(tnr_dmd->diver_sub,
170 						       offset);
171 }
172 
173 int cxd2880_tnrdmd_dvbt2_mon_l1_pre(struct cxd2880_tnrdmd *tnr_dmd,
174 				    struct cxd2880_dvbt2_l1pre
175 				    *l1_pre)
176 {
177 	u8 data[37];
178 	u8 sync_state = 0;
179 	u8 ts_lock = 0;
180 	u8 unlock_detected = 0;
181 	u8 version = 0;
182 	enum cxd2880_dvbt2_profile profile;
183 	int ret;
184 
185 	if (!tnr_dmd || !l1_pre)
186 		return -EINVAL;
187 
188 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
189 		return -EINVAL;
190 
191 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
192 		return -EINVAL;
193 
194 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
195 		return -EINVAL;
196 
197 	ret = slvt_freeze_reg(tnr_dmd);
198 	if (ret)
199 		return ret;
200 
201 	ret =
202 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
203 					       &ts_lock,
204 					       &unlock_detected);
205 	if (ret) {
206 		slvt_unfreeze_reg(tnr_dmd);
207 		return ret;
208 	}
209 
210 	if (sync_state < 5) {
211 		if (tnr_dmd->diver_mode ==
212 		    CXD2880_TNRDMD_DIVERMODE_MAIN) {
213 			ret =
214 			    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
215 			    (tnr_dmd, &sync_state, &unlock_detected);
216 			if (ret) {
217 				slvt_unfreeze_reg(tnr_dmd);
218 				return ret;
219 			}
220 
221 			if (sync_state < 5) {
222 				slvt_unfreeze_reg(tnr_dmd);
223 				return -EAGAIN;
224 			}
225 		} else {
226 			slvt_unfreeze_reg(tnr_dmd);
227 			return -EAGAIN;
228 		}
229 	}
230 
231 	ret = cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd, &profile);
232 	if (ret) {
233 		slvt_unfreeze_reg(tnr_dmd);
234 		return ret;
235 	}
236 
237 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
238 				     CXD2880_IO_TGT_DMD,
239 				     0x00, 0x0b);
240 	if (ret) {
241 		slvt_unfreeze_reg(tnr_dmd);
242 		return ret;
243 	}
244 
245 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
246 				     CXD2880_IO_TGT_DMD,
247 				     0x61, data, sizeof(data));
248 	if (ret) {
249 		slvt_unfreeze_reg(tnr_dmd);
250 		return ret;
251 	}
252 	slvt_unfreeze_reg(tnr_dmd);
253 
254 	l1_pre->type = (enum cxd2880_dvbt2_l1pre_type)data[0];
255 	l1_pre->bw_ext = data[1] & 0x01;
256 	l1_pre->s1 = (enum cxd2880_dvbt2_s1)(data[2] & 0x07);
257 	l1_pre->s2 = data[3] & 0x0f;
258 	l1_pre->l1_rep = data[4] & 0x01;
259 	l1_pre->gi = (enum cxd2880_dvbt2_guard)(data[5] & 0x07);
260 	l1_pre->papr = (enum cxd2880_dvbt2_papr)(data[6] & 0x0f);
261 	l1_pre->mod =
262 	    (enum cxd2880_dvbt2_l1post_constell)(data[7] & 0x0f);
263 	l1_pre->cr = (enum cxd2880_dvbt2_l1post_cr)(data[8] & 0x03);
264 	l1_pre->fec =
265 	    (enum cxd2880_dvbt2_l1post_fec_type)(data[9] & 0x03);
266 	l1_pre->l1_post_size = (data[10] & 0x03) << 16;
267 	l1_pre->l1_post_size |= (data[11]) << 8;
268 	l1_pre->l1_post_size |= (data[12]);
269 	l1_pre->l1_post_info_size = (data[13] & 0x03) << 16;
270 	l1_pre->l1_post_info_size |= (data[14]) << 8;
271 	l1_pre->l1_post_info_size |= (data[15]);
272 	l1_pre->pp = (enum cxd2880_dvbt2_pp)(data[16] & 0x0f);
273 	l1_pre->tx_id_availability = data[17];
274 	l1_pre->cell_id = (data[18] << 8);
275 	l1_pre->cell_id |= (data[19]);
276 	l1_pre->network_id = (data[20] << 8);
277 	l1_pre->network_id |= (data[21]);
278 	l1_pre->sys_id = (data[22] << 8);
279 	l1_pre->sys_id |= (data[23]);
280 	l1_pre->num_frames = data[24];
281 	l1_pre->num_symbols = (data[25] & 0x0f) << 8;
282 	l1_pre->num_symbols |= data[26];
283 	l1_pre->regen = data[27] & 0x07;
284 	l1_pre->post_ext = data[28] & 0x01;
285 	l1_pre->num_rf_freqs = data[29] & 0x07;
286 	l1_pre->rf_idx = data[30] & 0x07;
287 	version = (data[31] & 0x03) << 2;
288 	version |= (data[32] & 0xc0) >> 6;
289 	l1_pre->t2_version = (enum cxd2880_dvbt2_version)version;
290 	l1_pre->l1_post_scrambled = (data[32] & 0x20) >> 5;
291 	l1_pre->t2_base_lite = (data[32] & 0x10) >> 4;
292 	l1_pre->crc32 = (data[33] << 24);
293 	l1_pre->crc32 |= (data[34] << 16);
294 	l1_pre->crc32 |= (data[35] << 8);
295 	l1_pre->crc32 |= data[36];
296 
297 	if (profile == CXD2880_DVBT2_PROFILE_BASE) {
298 		switch ((l1_pre->s2 >> 1)) {
299 		case CXD2880_DVBT2_BASE_S2_M1K_G_ANY:
300 			l1_pre->fft_mode = CXD2880_DVBT2_M1K;
301 			break;
302 		case CXD2880_DVBT2_BASE_S2_M2K_G_ANY:
303 			l1_pre->fft_mode = CXD2880_DVBT2_M2K;
304 			break;
305 		case CXD2880_DVBT2_BASE_S2_M4K_G_ANY:
306 			l1_pre->fft_mode = CXD2880_DVBT2_M4K;
307 			break;
308 		case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT:
309 		case CXD2880_DVBT2_BASE_S2_M8K_G_DVBT2:
310 			l1_pre->fft_mode = CXD2880_DVBT2_M8K;
311 			break;
312 		case CXD2880_DVBT2_BASE_S2_M16K_G_ANY:
313 			l1_pre->fft_mode = CXD2880_DVBT2_M16K;
314 			break;
315 		case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT:
316 		case CXD2880_DVBT2_BASE_S2_M32K_G_DVBT2:
317 			l1_pre->fft_mode = CXD2880_DVBT2_M32K;
318 			break;
319 		default:
320 			return -EAGAIN;
321 		}
322 	} else if (profile == CXD2880_DVBT2_PROFILE_LITE) {
323 		switch ((l1_pre->s2 >> 1)) {
324 		case CXD2880_DVBT2_LITE_S2_M2K_G_ANY:
325 			l1_pre->fft_mode = CXD2880_DVBT2_M2K;
326 			break;
327 		case CXD2880_DVBT2_LITE_S2_M4K_G_ANY:
328 			l1_pre->fft_mode = CXD2880_DVBT2_M4K;
329 			break;
330 		case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT:
331 		case CXD2880_DVBT2_LITE_S2_M8K_G_DVBT2:
332 			l1_pre->fft_mode = CXD2880_DVBT2_M8K;
333 			break;
334 		case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT:
335 		case CXD2880_DVBT2_LITE_S2_M16K_G_DVBT2:
336 			l1_pre->fft_mode = CXD2880_DVBT2_M16K;
337 			break;
338 		default:
339 			return -EAGAIN;
340 		}
341 	} else {
342 		return -EAGAIN;
343 	}
344 
345 	l1_pre->mixed = l1_pre->s2 & 0x01;
346 
347 	return ret;
348 }
349 
350 int cxd2880_tnrdmd_dvbt2_mon_version(struct cxd2880_tnrdmd
351 				     *tnr_dmd,
352 				     enum cxd2880_dvbt2_version
353 				     *ver)
354 {
355 	u8 data[2];
356 	u8 sync_state = 0;
357 	u8 ts_lock = 0;
358 	u8 unlock_detected = 0;
359 	u8 version = 0;
360 	int ret;
361 
362 	if (!tnr_dmd || !ver)
363 		return -EINVAL;
364 
365 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
366 		return -EINVAL;
367 
368 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
369 		return -EINVAL;
370 
371 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
372 		return -EINVAL;
373 
374 	ret = slvt_freeze_reg(tnr_dmd);
375 	if (ret)
376 		return ret;
377 
378 	ret =
379 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
380 					       &ts_lock,
381 					       &unlock_detected);
382 	if (ret) {
383 		slvt_unfreeze_reg(tnr_dmd);
384 		return ret;
385 	}
386 
387 	if (sync_state < 5) {
388 		if (tnr_dmd->diver_mode ==
389 		    CXD2880_TNRDMD_DIVERMODE_MAIN) {
390 			ret =
391 			    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
392 			    (tnr_dmd, &sync_state, &unlock_detected);
393 			if (ret) {
394 				slvt_unfreeze_reg(tnr_dmd);
395 				return ret;
396 			}
397 
398 			if (sync_state < 5) {
399 				slvt_unfreeze_reg(tnr_dmd);
400 				return -EAGAIN;
401 			}
402 		} else {
403 			slvt_unfreeze_reg(tnr_dmd);
404 			return -EAGAIN;
405 		}
406 	}
407 
408 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
409 				     CXD2880_IO_TGT_DMD,
410 				     0x00, 0x0b);
411 	if (ret) {
412 		slvt_unfreeze_reg(tnr_dmd);
413 		return ret;
414 	}
415 
416 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
417 				     CXD2880_IO_TGT_DMD,
418 				     0x80, data, sizeof(data));
419 	if (ret) {
420 		slvt_unfreeze_reg(tnr_dmd);
421 		return ret;
422 	}
423 
424 	slvt_unfreeze_reg(tnr_dmd);
425 
426 	version = ((data[0] & 0x03) << 2);
427 	version |= ((data[1] & 0xc0) >> 6);
428 	*ver = (enum cxd2880_dvbt2_version)version;
429 
430 	return ret;
431 }
432 
433 int cxd2880_tnrdmd_dvbt2_mon_ofdm(struct cxd2880_tnrdmd *tnr_dmd,
434 				  struct cxd2880_dvbt2_ofdm *ofdm)
435 {
436 	u8 data[5];
437 	u8 sync_state = 0;
438 	u8 ts_lock = 0;
439 	u8 unlock_detected = 0;
440 	int ret;
441 
442 	if (!tnr_dmd || !ofdm)
443 		return -EINVAL;
444 
445 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
446 		return -EINVAL;
447 
448 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
449 		return -EINVAL;
450 
451 	ret = slvt_freeze_reg(tnr_dmd);
452 	if (ret)
453 		return ret;
454 
455 	ret =
456 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
457 					       &ts_lock,
458 					       &unlock_detected);
459 	if (ret) {
460 		slvt_unfreeze_reg(tnr_dmd);
461 		return ret;
462 	}
463 
464 	if (sync_state != 6) {
465 		slvt_unfreeze_reg(tnr_dmd);
466 
467 		ret = -EAGAIN;
468 
469 		if (tnr_dmd->diver_mode ==
470 		    CXD2880_TNRDMD_DIVERMODE_MAIN)
471 			ret =
472 			    cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd->diver_sub,
473 							  ofdm);
474 
475 		return ret;
476 	}
477 
478 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
479 				     CXD2880_IO_TGT_DMD,
480 				     0x00, 0x0b);
481 	if (ret) {
482 		slvt_unfreeze_reg(tnr_dmd);
483 		return ret;
484 	}
485 
486 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
487 				     CXD2880_IO_TGT_DMD,
488 				     0x1d, data, sizeof(data));
489 	if (ret) {
490 		slvt_unfreeze_reg(tnr_dmd);
491 		return ret;
492 	}
493 
494 	slvt_unfreeze_reg(tnr_dmd);
495 
496 	ofdm->mixed = ((data[0] & 0x20) ? 1 : 0);
497 	ofdm->is_miso = ((data[0] & 0x10) >> 4);
498 	ofdm->mode = (enum cxd2880_dvbt2_mode)(data[0] & 0x07);
499 	ofdm->gi = (enum cxd2880_dvbt2_guard)((data[1] & 0x70) >> 4);
500 	ofdm->pp = (enum cxd2880_dvbt2_pp)(data[1] & 0x07);
501 	ofdm->bw_ext = (data[2] & 0x10) >> 4;
502 	ofdm->papr = (enum cxd2880_dvbt2_papr)(data[2] & 0x0f);
503 	ofdm->num_symbols = (data[3] << 8) | data[4];
504 
505 	return 0;
506 }
507 
508 int cxd2880_tnrdmd_dvbt2_mon_data_plps(struct cxd2880_tnrdmd
509 				       *tnr_dmd, u8 *plp_ids,
510 				       u8 *num_plps)
511 {
512 	u8 l1_post_ok = 0;
513 	int ret;
514 
515 	if (!tnr_dmd || !num_plps)
516 		return -EINVAL;
517 
518 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
519 		return -EINVAL;
520 
521 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
522 		return -EINVAL;
523 
524 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
525 		return -EINVAL;
526 
527 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
528 				     CXD2880_IO_TGT_DMD,
529 				     0x00, 0x0b);
530 	if (ret)
531 		return ret;
532 
533 	ret = slvt_freeze_reg(tnr_dmd);
534 	if (ret)
535 		return ret;
536 
537 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
538 				     CXD2880_IO_TGT_DMD,
539 				     0x86, &l1_post_ok, 1);
540 	if (ret) {
541 		slvt_unfreeze_reg(tnr_dmd);
542 		return ret;
543 	}
544 
545 	if (!(l1_post_ok & 0x01)) {
546 		slvt_unfreeze_reg(tnr_dmd);
547 		return -EAGAIN;
548 	}
549 
550 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
551 				     CXD2880_IO_TGT_DMD,
552 				     0xc1, num_plps, 1);
553 	if (ret) {
554 		slvt_unfreeze_reg(tnr_dmd);
555 		return ret;
556 	}
557 
558 	if (*num_plps == 0) {
559 		slvt_unfreeze_reg(tnr_dmd);
560 		return -EINVAL;
561 	}
562 
563 	if (!plp_ids) {
564 		slvt_unfreeze_reg(tnr_dmd);
565 		return 0;
566 	}
567 
568 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
569 				     CXD2880_IO_TGT_DMD,
570 				     0xc2,
571 				     plp_ids,
572 				     ((*num_plps > 62) ?
573 				     62 : *num_plps));
574 	if (ret) {
575 		slvt_unfreeze_reg(tnr_dmd);
576 		return ret;
577 	}
578 
579 	if (*num_plps > 62) {
580 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
581 					     CXD2880_IO_TGT_DMD,
582 					     0x00, 0x0c);
583 		if (ret) {
584 			slvt_unfreeze_reg(tnr_dmd);
585 			return ret;
586 		}
587 
588 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
589 					     CXD2880_IO_TGT_DMD,
590 					     0x10, plp_ids + 62,
591 					     *num_plps - 62);
592 		if (ret) {
593 			slvt_unfreeze_reg(tnr_dmd);
594 			return ret;
595 		}
596 	}
597 
598 	slvt_unfreeze_reg(tnr_dmd);
599 
600 	return 0;
601 }
602 
603 int cxd2880_tnrdmd_dvbt2_mon_active_plp(struct cxd2880_tnrdmd
604 					*tnr_dmd,
605 					enum
606 					cxd2880_dvbt2_plp_btype
607 					type,
608 					struct cxd2880_dvbt2_plp
609 					*plp_info)
610 {
611 	u8 data[20];
612 	u8 addr = 0;
613 	u8 index = 0;
614 	u8 l1_post_ok = 0;
615 	int ret;
616 
617 	if (!tnr_dmd || !plp_info)
618 		return -EINVAL;
619 
620 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
621 		return -EINVAL;
622 
623 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
624 		return -EINVAL;
625 
626 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
627 		return -EINVAL;
628 
629 	ret = slvt_freeze_reg(tnr_dmd);
630 	if (ret)
631 		return ret;
632 
633 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
634 				     CXD2880_IO_TGT_DMD,
635 				     0x00, 0x0b);
636 	if (ret) {
637 		slvt_unfreeze_reg(tnr_dmd);
638 		return ret;
639 	}
640 
641 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
642 				     CXD2880_IO_TGT_DMD,
643 				     0x86, &l1_post_ok, 1);
644 	if (ret) {
645 		slvt_unfreeze_reg(tnr_dmd);
646 		return ret;
647 	}
648 
649 	if (!l1_post_ok) {
650 		slvt_unfreeze_reg(tnr_dmd);
651 		return -EAGAIN;
652 	}
653 
654 	if (type == CXD2880_DVBT2_PLP_COMMON)
655 		addr = 0xa9;
656 	else
657 		addr = 0x96;
658 
659 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
660 				     CXD2880_IO_TGT_DMD,
661 				     addr, data, sizeof(data));
662 	if (ret) {
663 		slvt_unfreeze_reg(tnr_dmd);
664 		return ret;
665 	}
666 
667 	slvt_unfreeze_reg(tnr_dmd);
668 
669 	if (type == CXD2880_DVBT2_PLP_COMMON && !data[13])
670 		return -EAGAIN;
671 
672 	plp_info->id = data[index++];
673 	plp_info->type =
674 	    (enum cxd2880_dvbt2_plp_type)(data[index++] & 0x07);
675 	plp_info->payload =
676 	    (enum cxd2880_dvbt2_plp_payload)(data[index++] & 0x1f);
677 	plp_info->ff = data[index++] & 0x01;
678 	plp_info->first_rf_idx = data[index++] & 0x07;
679 	plp_info->first_frm_idx = data[index++];
680 	plp_info->group_id = data[index++];
681 	plp_info->plp_cr =
682 	    (enum cxd2880_dvbt2_plp_code_rate)(data[index++] & 0x07);
683 	plp_info->constell =
684 	    (enum cxd2880_dvbt2_plp_constell)(data[index++] & 0x07);
685 	plp_info->rot = data[index++] & 0x01;
686 	plp_info->fec =
687 	    (enum cxd2880_dvbt2_plp_fec)(data[index++] & 0x03);
688 	plp_info->num_blocks_max = (data[index++] & 0x03) << 8;
689 	plp_info->num_blocks_max |= data[index++];
690 	plp_info->frm_int = data[index++];
691 	plp_info->til_len = data[index++];
692 	plp_info->til_type = data[index++] & 0x01;
693 
694 	plp_info->in_band_a_flag = data[index++] & 0x01;
695 	plp_info->rsvd = data[index++] << 8;
696 	plp_info->rsvd |= data[index++];
697 
698 	plp_info->in_band_b_flag =
699 	    (plp_info->rsvd & 0x8000) >> 15;
700 	plp_info->plp_mode =
701 	    (enum cxd2880_dvbt2_plp_mode)((plp_info->rsvd & 0x000c) >> 2);
702 	plp_info->static_flag = (plp_info->rsvd & 0x0002) >> 1;
703 	plp_info->static_padding_flag = plp_info->rsvd & 0x0001;
704 	plp_info->rsvd = (plp_info->rsvd & 0x7ff0) >> 4;
705 
706 	return 0;
707 }
708 
709 int cxd2880_tnrdmd_dvbt2_mon_data_plp_error(struct cxd2880_tnrdmd
710 					    *tnr_dmd,
711 					    u8 *plp_error)
712 {
713 	u8 data;
714 	int ret;
715 
716 	if (!tnr_dmd || !plp_error)
717 		return -EINVAL;
718 
719 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
720 		return -EINVAL;
721 
722 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
723 		return -EINVAL;
724 
725 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
726 		return -EINVAL;
727 
728 	ret = slvt_freeze_reg(tnr_dmd);
729 	if (ret)
730 		return ret;
731 
732 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
733 				     CXD2880_IO_TGT_DMD,
734 				     0x00, 0x0b);
735 	if (ret) {
736 		slvt_unfreeze_reg(tnr_dmd);
737 		return ret;
738 	}
739 
740 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
741 				     CXD2880_IO_TGT_DMD,
742 				     0x86, &data, 1);
743 	if (ret) {
744 		slvt_unfreeze_reg(tnr_dmd);
745 		return ret;
746 	}
747 
748 	if ((data & 0x01) == 0x00) {
749 		slvt_unfreeze_reg(tnr_dmd);
750 		return -EAGAIN;
751 	}
752 
753 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
754 				     CXD2880_IO_TGT_DMD,
755 				     0xc0, &data, 1);
756 	if (ret) {
757 		slvt_unfreeze_reg(tnr_dmd);
758 		return ret;
759 	}
760 
761 	slvt_unfreeze_reg(tnr_dmd);
762 
763 	*plp_error = data & 0x01;
764 
765 	return 0;
766 }
767 
768 int cxd2880_tnrdmd_dvbt2_mon_l1_change(struct cxd2880_tnrdmd
769 				       *tnr_dmd, u8 *l1_change)
770 {
771 	u8 data;
772 	u8 sync_state = 0;
773 	u8 ts_lock = 0;
774 	u8 unlock_detected = 0;
775 	int ret;
776 
777 	if (!tnr_dmd || !l1_change)
778 		return -EINVAL;
779 
780 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
781 		return -EINVAL;
782 
783 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
784 		return -EINVAL;
785 
786 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
787 		return -EINVAL;
788 
789 	ret = slvt_freeze_reg(tnr_dmd);
790 	if (ret)
791 		return ret;
792 
793 	ret =
794 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
795 					       &ts_lock,
796 					       &unlock_detected);
797 	if (ret) {
798 		slvt_unfreeze_reg(tnr_dmd);
799 		return ret;
800 	}
801 
802 	if (sync_state < 5) {
803 		if (tnr_dmd->diver_mode ==
804 		    CXD2880_TNRDMD_DIVERMODE_MAIN) {
805 			ret =
806 			    cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub
807 			    (tnr_dmd, &sync_state, &unlock_detected);
808 			if (ret) {
809 				slvt_unfreeze_reg(tnr_dmd);
810 				return ret;
811 			}
812 
813 			if (sync_state < 5) {
814 				slvt_unfreeze_reg(tnr_dmd);
815 				return -EAGAIN;
816 			}
817 		} else {
818 			slvt_unfreeze_reg(tnr_dmd);
819 			return -EAGAIN;
820 		}
821 	}
822 
823 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
824 				     CXD2880_IO_TGT_DMD,
825 				     0x00, 0x0b);
826 	if (ret) {
827 		slvt_unfreeze_reg(tnr_dmd);
828 		return ret;
829 	}
830 
831 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
832 				     CXD2880_IO_TGT_DMD,
833 				     0x5f, &data, sizeof(data));
834 	if (ret) {
835 		slvt_unfreeze_reg(tnr_dmd);
836 		return ret;
837 	}
838 
839 	*l1_change = data & 0x01;
840 	if (*l1_change) {
841 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
842 					     CXD2880_IO_TGT_DMD,
843 					     0x00, 0x22);
844 		if (ret) {
845 			slvt_unfreeze_reg(tnr_dmd);
846 			return ret;
847 		}
848 
849 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
850 					     CXD2880_IO_TGT_DMD,
851 					     0x16, 0x01);
852 		if (ret) {
853 			slvt_unfreeze_reg(tnr_dmd);
854 			return ret;
855 		}
856 	}
857 	slvt_unfreeze_reg(tnr_dmd);
858 
859 	return 0;
860 }
861 
862 int cxd2880_tnrdmd_dvbt2_mon_l1_post(struct cxd2880_tnrdmd
863 				     *tnr_dmd,
864 				     struct cxd2880_dvbt2_l1post
865 				     *l1_post)
866 {
867 	u8 data[16];
868 	int ret;
869 
870 	if (!tnr_dmd || !l1_post)
871 		return -EINVAL;
872 
873 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
874 		return -EINVAL;
875 
876 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
877 		return -EINVAL;
878 
879 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
880 		return -EINVAL;
881 
882 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
883 				     CXD2880_IO_TGT_DMD,
884 				     0x00, 0x0b);
885 	if (ret)
886 		return ret;
887 
888 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
889 				     CXD2880_IO_TGT_DMD,
890 				     0x86, data, sizeof(data));
891 	if (ret)
892 		return ret;
893 
894 	if (!(data[0] & 0x01))
895 		return -EAGAIN;
896 
897 	l1_post->sub_slices_per_frame = (data[1] & 0x7f) << 8;
898 	l1_post->sub_slices_per_frame |= data[2];
899 	l1_post->num_plps = data[3];
900 	l1_post->num_aux = data[4] & 0x0f;
901 	l1_post->aux_cfg_rfu = data[5];
902 	l1_post->rf_idx = data[6] & 0x07;
903 	l1_post->freq = data[7] << 24;
904 	l1_post->freq |= data[8] << 16;
905 	l1_post->freq |= data[9] << 8;
906 	l1_post->freq |= data[10];
907 	l1_post->fef_type = data[11] & 0x0f;
908 	l1_post->fef_length = data[12] << 16;
909 	l1_post->fef_length |= data[13] << 8;
910 	l1_post->fef_length |= data[14];
911 	l1_post->fef_intvl = data[15];
912 
913 	return 0;
914 }
915 
916 int cxd2880_tnrdmd_dvbt2_mon_bbheader(struct cxd2880_tnrdmd
917 				      *tnr_dmd,
918 				      enum cxd2880_dvbt2_plp_btype
919 				      type,
920 				      struct cxd2880_dvbt2_bbheader
921 				      *bbheader)
922 {
923 	u8 sync_state = 0;
924 	u8 ts_lock = 0;
925 	u8 unlock_detected = 0;
926 	u8 data[14];
927 	u8 addr = 0;
928 	int ret;
929 
930 	if (!tnr_dmd || !bbheader)
931 		return -EINVAL;
932 
933 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
934 		return -EINVAL;
935 
936 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
937 		return -EINVAL;
938 
939 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
940 		return -EINVAL;
941 
942 	ret = slvt_freeze_reg(tnr_dmd);
943 	if (ret)
944 		return ret;
945 
946 	ret =
947 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
948 						       &ts_lock,
949 						       &unlock_detected);
950 	if (ret) {
951 		slvt_unfreeze_reg(tnr_dmd);
952 		return ret;
953 	}
954 
955 	if (!ts_lock) {
956 		slvt_unfreeze_reg(tnr_dmd);
957 		return -EAGAIN;
958 	}
959 
960 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
961 				     CXD2880_IO_TGT_DMD,
962 				     0x00, 0x0b);
963 	if (ret) {
964 		slvt_unfreeze_reg(tnr_dmd);
965 		return ret;
966 	}
967 
968 	if (type == CXD2880_DVBT2_PLP_COMMON) {
969 		u8 l1_post_ok;
970 		u8 data;
971 
972 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
973 					     CXD2880_IO_TGT_DMD,
974 					     0x86, &l1_post_ok, 1);
975 		if (ret) {
976 			slvt_unfreeze_reg(tnr_dmd);
977 			return ret;
978 		}
979 
980 		if (!(l1_post_ok & 0x01)) {
981 			slvt_unfreeze_reg(tnr_dmd);
982 			return -EAGAIN;
983 		}
984 
985 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
986 					     CXD2880_IO_TGT_DMD,
987 					     0xb6, &data, 1);
988 		if (ret) {
989 			slvt_unfreeze_reg(tnr_dmd);
990 			return ret;
991 		}
992 
993 		if (data == 0) {
994 			slvt_unfreeze_reg(tnr_dmd);
995 			return -EAGAIN;
996 		}
997 	}
998 
999 	if (type == CXD2880_DVBT2_PLP_COMMON)
1000 		addr = 0x51;
1001 	else
1002 		addr = 0x42;
1003 
1004 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1005 				     CXD2880_IO_TGT_DMD,
1006 				     addr, data, sizeof(data));
1007 	if (ret) {
1008 		slvt_unfreeze_reg(tnr_dmd);
1009 		return ret;
1010 	}
1011 
1012 	slvt_unfreeze_reg(tnr_dmd);
1013 
1014 	bbheader->stream_input =
1015 	    (enum cxd2880_dvbt2_stream)((data[0] >> 6) & 0x03);
1016 	bbheader->is_single_input_stream = (data[0] >> 5) & 0x01;
1017 	bbheader->is_constant_coding_modulation =
1018 	    (data[0] >> 4) & 0x01;
1019 	bbheader->issy_indicator = (data[0] >> 3) & 0x01;
1020 	bbheader->null_packet_deletion = (data[0] >> 2) & 0x01;
1021 	bbheader->ext = data[0] & 0x03;
1022 
1023 	bbheader->input_stream_identifier = data[1];
1024 	bbheader->plp_mode =
1025 	    (data[3] & 0x01) ? CXD2880_DVBT2_PLP_MODE_HEM :
1026 	    CXD2880_DVBT2_PLP_MODE_NM;
1027 	bbheader->data_field_length = (data[4] << 8) | data[5];
1028 
1029 	if (bbheader->plp_mode == CXD2880_DVBT2_PLP_MODE_NM) {
1030 		bbheader->user_packet_length =
1031 		    (data[6] << 8) | data[7];
1032 		bbheader->sync_byte = data[8];
1033 		bbheader->issy = 0;
1034 	} else {
1035 		bbheader->user_packet_length = 0;
1036 		bbheader->sync_byte = 0;
1037 		bbheader->issy =
1038 		    (data[11] << 16) | (data[12] << 8) | data[13];
1039 	}
1040 
1041 	return 0;
1042 }
1043 
1044 int cxd2880_tnrdmd_dvbt2_mon_in_bandb_ts_rate(struct cxd2880_tnrdmd
1045 					      *tnr_dmd,
1046 					      enum
1047 					      cxd2880_dvbt2_plp_btype
1048 					      type,
1049 					      u32 *ts_rate_bps)
1050 {
1051 	u8 sync_state = 0;
1052 	u8 ts_lock = 0;
1053 	u8 unlock_detected = 0;
1054 	u8 l1_post_ok = 0;
1055 	u8 data[4];
1056 	u8 addr = 0;
1057 
1058 	int ret;
1059 
1060 	if (!tnr_dmd || !ts_rate_bps)
1061 		return -EINVAL;
1062 
1063 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1064 		return -EINVAL;
1065 
1066 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1067 		return -EINVAL;
1068 
1069 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1070 		return -EINVAL;
1071 
1072 	ret = slvt_freeze_reg(tnr_dmd);
1073 	if (ret)
1074 		return ret;
1075 
1076 	ret =
1077 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1078 					       &ts_lock,
1079 					       &unlock_detected);
1080 	if (ret) {
1081 		slvt_unfreeze_reg(tnr_dmd);
1082 		return ret;
1083 	}
1084 
1085 	if (!ts_lock) {
1086 		slvt_unfreeze_reg(tnr_dmd);
1087 		return -EAGAIN;
1088 	}
1089 
1090 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1091 				     CXD2880_IO_TGT_DMD,
1092 				     0x00, 0x0b);
1093 	if (ret) {
1094 		slvt_unfreeze_reg(tnr_dmd);
1095 		return ret;
1096 	}
1097 
1098 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1099 				     CXD2880_IO_TGT_DMD,
1100 				     0x86, &l1_post_ok, 1);
1101 	if (ret) {
1102 		slvt_unfreeze_reg(tnr_dmd);
1103 		return ret;
1104 	}
1105 
1106 	if (!(l1_post_ok & 0x01)) {
1107 		slvt_unfreeze_reg(tnr_dmd);
1108 		return -EAGAIN;
1109 	}
1110 
1111 	if (type == CXD2880_DVBT2_PLP_COMMON)
1112 		addr = 0xba;
1113 	else
1114 		addr = 0xa7;
1115 
1116 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1117 				     CXD2880_IO_TGT_DMD,
1118 				     addr, &data[0], 1);
1119 	if (ret) {
1120 		slvt_unfreeze_reg(tnr_dmd);
1121 		return ret;
1122 	}
1123 
1124 	if ((data[0] & 0x80) == 0x00) {
1125 		slvt_unfreeze_reg(tnr_dmd);
1126 		return -EAGAIN;
1127 	}
1128 
1129 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1130 				     CXD2880_IO_TGT_DMD,
1131 				     0x00, 0x25);
1132 	if (ret) {
1133 		slvt_unfreeze_reg(tnr_dmd);
1134 		return ret;
1135 	}
1136 
1137 	if (type == CXD2880_DVBT2_PLP_COMMON)
1138 		addr = 0xa6;
1139 	else
1140 		addr = 0xaa;
1141 
1142 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1143 				     CXD2880_IO_TGT_DMD,
1144 				     addr, &data[0], 4);
1145 	if (ret) {
1146 		slvt_unfreeze_reg(tnr_dmd);
1147 		return ret;
1148 	}
1149 
1150 	*ts_rate_bps = ((data[0] & 0x07) << 24) | (data[1] << 16) |
1151 		       (data[2] << 8) | data[3];
1152 
1153 	return 0;
1154 }
1155 
1156 int cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(struct cxd2880_tnrdmd
1157 					    *tnr_dmd,
1158 					    enum
1159 					    cxd2880_tnrdmd_spectrum_sense
1160 					    *sense)
1161 {
1162 	u8 sync_state = 0;
1163 	u8 ts_lock = 0;
1164 	u8 early_unlock = 0;
1165 	u8 data = 0;
1166 	int ret;
1167 
1168 	if (!tnr_dmd || !sense)
1169 		return -EINVAL;
1170 
1171 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1172 		return -EINVAL;
1173 
1174 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1175 		return -EINVAL;
1176 
1177 	ret = slvt_freeze_reg(tnr_dmd);
1178 	if (ret)
1179 		return ret;
1180 
1181 	ret =
1182 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state, &ts_lock,
1183 					       &early_unlock);
1184 	if (ret) {
1185 		slvt_unfreeze_reg(tnr_dmd);
1186 		return ret;
1187 	}
1188 
1189 	if (sync_state != 6) {
1190 		slvt_unfreeze_reg(tnr_dmd);
1191 
1192 		ret = -EAGAIN;
1193 
1194 		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
1195 			ret =
1196 			    cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd->diver_sub,
1197 								    sense);
1198 
1199 		return ret;
1200 	}
1201 
1202 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1203 				     CXD2880_IO_TGT_DMD,
1204 				     0x00, 0x0b);
1205 	if (ret) {
1206 		slvt_unfreeze_reg(tnr_dmd);
1207 		return ret;
1208 	}
1209 
1210 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1211 				     CXD2880_IO_TGT_DMD,
1212 				     0x2f, &data, sizeof(data));
1213 	if (ret) {
1214 		slvt_unfreeze_reg(tnr_dmd);
1215 		return ret;
1216 	}
1217 
1218 	slvt_unfreeze_reg(tnr_dmd);
1219 
1220 	*sense =
1221 	    (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
1222 	    CXD2880_TNRDMD_SPECTRUM_NORMAL;
1223 
1224 	return 0;
1225 }
1226 
1227 static int dvbt2_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
1228 			      u16 *reg_value)
1229 {
1230 	u8 sync_state = 0;
1231 	u8 ts_lock = 0;
1232 	u8 unlock_detected = 0;
1233 	u8 data[2];
1234 	int ret;
1235 
1236 	if (!tnr_dmd || !reg_value)
1237 		return -EINVAL;
1238 
1239 	ret = slvt_freeze_reg(tnr_dmd);
1240 	if (ret)
1241 		return ret;
1242 
1243 	ret =
1244 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1245 					       &ts_lock,
1246 					       &unlock_detected);
1247 	if (ret) {
1248 		slvt_unfreeze_reg(tnr_dmd);
1249 		return ret;
1250 	}
1251 
1252 	if (sync_state != 6) {
1253 		slvt_unfreeze_reg(tnr_dmd);
1254 		return -EAGAIN;
1255 	}
1256 
1257 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1258 				     CXD2880_IO_TGT_DMD,
1259 				     0x00, 0x0b);
1260 	if (ret) {
1261 		slvt_unfreeze_reg(tnr_dmd);
1262 		return ret;
1263 	}
1264 
1265 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1266 				     CXD2880_IO_TGT_DMD,
1267 				     0x13, data, sizeof(data));
1268 	if (ret) {
1269 		slvt_unfreeze_reg(tnr_dmd);
1270 		return ret;
1271 	}
1272 
1273 	slvt_unfreeze_reg(tnr_dmd);
1274 
1275 	*reg_value = (data[0] << 8) | data[1];
1276 
1277 	return ret;
1278 }
1279 
1280 static int dvbt2_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
1281 			  u32 reg_value, int *snr)
1282 {
1283 	if (!tnr_dmd || !snr)
1284 		return -EINVAL;
1285 
1286 	if (reg_value == 0)
1287 		return -EAGAIN;
1288 
1289 	if (reg_value > 10876)
1290 		reg_value = 10876;
1291 
1292 	*snr = intlog10(reg_value) - intlog10(12600 - reg_value);
1293 	*snr = (*snr + 839) / 1678 + 32000;
1294 
1295 	return 0;
1296 }
1297 
1298 int cxd2880_tnrdmd_dvbt2_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
1299 				 int *snr)
1300 {
1301 	u16 reg_value = 0;
1302 	int ret;
1303 
1304 	if (!tnr_dmd || !snr)
1305 		return -EINVAL;
1306 
1307 	*snr = -1000 * 1000;
1308 
1309 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1310 		return -EINVAL;
1311 
1312 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1313 		return -EINVAL;
1314 
1315 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1316 		return -EINVAL;
1317 
1318 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
1319 		ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
1320 		if (ret)
1321 			return ret;
1322 
1323 		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr);
1324 	} else {
1325 		int snr_main = 0;
1326 		int snr_sub = 0;
1327 
1328 		ret =
1329 		    cxd2880_tnrdmd_dvbt2_mon_snr_diver(tnr_dmd, snr, &snr_main,
1330 						       &snr_sub);
1331 	}
1332 
1333 	return ret;
1334 }
1335 
1336 int cxd2880_tnrdmd_dvbt2_mon_snr_diver(struct cxd2880_tnrdmd
1337 				       *tnr_dmd, int *snr,
1338 				       int *snr_main, int *snr_sub)
1339 {
1340 	u16 reg_value = 0;
1341 	u32 reg_value_sum = 0;
1342 	int ret;
1343 
1344 	if (!tnr_dmd || !snr || !snr_main || !snr_sub)
1345 		return -EINVAL;
1346 
1347 	*snr = -1000 * 1000;
1348 	*snr_main = -1000 * 1000;
1349 	*snr_sub = -1000 * 1000;
1350 
1351 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
1352 		return -EINVAL;
1353 
1354 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1355 		return -EINVAL;
1356 
1357 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1358 		return -EINVAL;
1359 
1360 	ret = dvbt2_read_snr_reg(tnr_dmd, &reg_value);
1361 	if (!ret) {
1362 		ret = dvbt2_calc_snr(tnr_dmd, reg_value, snr_main);
1363 		if (ret)
1364 			reg_value = 0;
1365 	} else if (ret == -EAGAIN) {
1366 		reg_value = 0;
1367 	} else {
1368 		return ret;
1369 	}
1370 
1371 	reg_value_sum += reg_value;
1372 
1373 	ret = dvbt2_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
1374 	if (!ret) {
1375 		ret = dvbt2_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
1376 		if (ret)
1377 			reg_value = 0;
1378 	} else if (ret == -EAGAIN) {
1379 		reg_value = 0;
1380 	} else {
1381 		return ret;
1382 	}
1383 
1384 	reg_value_sum += reg_value;
1385 
1386 	return dvbt2_calc_snr(tnr_dmd, reg_value_sum, snr);
1387 }
1388 
1389 int cxd2880_tnrdmd_dvbt2_mon_packet_error_number(struct
1390 						 cxd2880_tnrdmd
1391 						 *tnr_dmd,
1392 						 u32 *pen)
1393 {
1394 	int ret;
1395 	u8 data[3];
1396 
1397 	if (!tnr_dmd || !pen)
1398 		return -EINVAL;
1399 
1400 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1401 		return -EINVAL;
1402 
1403 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1404 		return -EINVAL;
1405 
1406 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1407 		return -EINVAL;
1408 
1409 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1410 				     CXD2880_IO_TGT_DMD,
1411 				     0x00, 0x0b);
1412 	if (ret)
1413 		return ret;
1414 
1415 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1416 				     CXD2880_IO_TGT_DMD,
1417 				     0x39, data, sizeof(data));
1418 	if (ret)
1419 		return ret;
1420 
1421 	if (!(data[0] & 0x01))
1422 		return -EAGAIN;
1423 
1424 	*pen = ((data[1] << 8) | data[2]);
1425 
1426 	return ret;
1427 }
1428 
1429 int cxd2880_tnrdmd_dvbt2_mon_sampling_offset(struct cxd2880_tnrdmd
1430 					     *tnr_dmd, int *ppm)
1431 {
1432 	u8 ctl_val_reg[5];
1433 	u8 nominal_rate_reg[5];
1434 	u32 trl_ctl_val = 0;
1435 	u32 trcg_nominal_rate = 0;
1436 	int num;
1437 	int den;
1438 	int ret;
1439 	u8 sync_state = 0;
1440 	u8 ts_lock = 0;
1441 	u8 unlock_detected = 0;
1442 	s8 diff_upper = 0;
1443 
1444 	if (!tnr_dmd || !ppm)
1445 		return -EINVAL;
1446 
1447 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1448 		return -EINVAL;
1449 
1450 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1451 		return -EINVAL;
1452 
1453 	ret = slvt_freeze_reg(tnr_dmd);
1454 	if (ret)
1455 		return ret;
1456 
1457 	ret =
1458 	    cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_state,
1459 					       &ts_lock,
1460 					       &unlock_detected);
1461 	if (ret) {
1462 		slvt_unfreeze_reg(tnr_dmd);
1463 		return ret;
1464 	}
1465 
1466 	if (sync_state != 6) {
1467 		slvt_unfreeze_reg(tnr_dmd);
1468 		return -EAGAIN;
1469 	}
1470 
1471 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1472 				     CXD2880_IO_TGT_DMD,
1473 				     0x00, 0x0b);
1474 	if (ret) {
1475 		slvt_unfreeze_reg(tnr_dmd);
1476 		return ret;
1477 	}
1478 
1479 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1480 				     CXD2880_IO_TGT_DMD,
1481 				     0x34, ctl_val_reg,
1482 				     sizeof(ctl_val_reg));
1483 	if (ret) {
1484 		slvt_unfreeze_reg(tnr_dmd);
1485 		return ret;
1486 	}
1487 
1488 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1489 				     CXD2880_IO_TGT_DMD,
1490 				     0x00, 0x04);
1491 	if (ret) {
1492 		slvt_unfreeze_reg(tnr_dmd);
1493 		return ret;
1494 	}
1495 
1496 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1497 				     CXD2880_IO_TGT_DMD,
1498 				     0x10, nominal_rate_reg,
1499 				     sizeof(nominal_rate_reg));
1500 	if (ret) {
1501 		slvt_unfreeze_reg(tnr_dmd);
1502 		return ret;
1503 	}
1504 
1505 	slvt_unfreeze_reg(tnr_dmd);
1506 
1507 	diff_upper =
1508 	    (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
1509 
1510 	if (diff_upper < -1 || diff_upper > 1)
1511 		return -EAGAIN;
1512 
1513 	trl_ctl_val = ctl_val_reg[1] << 24;
1514 	trl_ctl_val |= ctl_val_reg[2] << 16;
1515 	trl_ctl_val |= ctl_val_reg[3] << 8;
1516 	trl_ctl_val |= ctl_val_reg[4];
1517 
1518 	trcg_nominal_rate = nominal_rate_reg[1] << 24;
1519 	trcg_nominal_rate |= nominal_rate_reg[2] << 16;
1520 	trcg_nominal_rate |= nominal_rate_reg[3] << 8;
1521 	trcg_nominal_rate |= nominal_rate_reg[4];
1522 
1523 	trl_ctl_val >>= 1;
1524 	trcg_nominal_rate >>= 1;
1525 
1526 	if (diff_upper == 1)
1527 		num =
1528 		    (int)((trl_ctl_val + 0x80000000u) -
1529 			  trcg_nominal_rate);
1530 	else if (diff_upper == -1)
1531 		num =
1532 		    -(int)((trcg_nominal_rate + 0x80000000u) -
1533 			   trl_ctl_val);
1534 	else
1535 		num = (int)(trl_ctl_val - trcg_nominal_rate);
1536 
1537 	den = (nominal_rate_reg[0] & 0x7f) << 24;
1538 	den |= nominal_rate_reg[1] << 16;
1539 	den |= nominal_rate_reg[2] << 8;
1540 	den |= nominal_rate_reg[3];
1541 	den = (den + (390625 / 2)) / 390625;
1542 
1543 	den >>= 1;
1544 
1545 	if (num >= 0)
1546 		*ppm = (num + (den / 2)) / den;
1547 	else
1548 		*ppm = (num - (den / 2)) / den;
1549 
1550 	return 0;
1551 }
1552 
1553 int cxd2880_tnrdmd_dvbt2_mon_sampling_offset_sub(struct
1554 						 cxd2880_tnrdmd
1555 						 *tnr_dmd,
1556 						 int *ppm)
1557 {
1558 	if (!tnr_dmd || !ppm)
1559 		return -EINVAL;
1560 
1561 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
1562 		return -EINVAL;
1563 
1564 	return cxd2880_tnrdmd_dvbt2_mon_sampling_offset(tnr_dmd->diver_sub,
1565 							ppm);
1566 }
1567 
1568 int cxd2880_tnrdmd_dvbt2_mon_qam(struct cxd2880_tnrdmd *tnr_dmd,
1569 				 enum cxd2880_dvbt2_plp_btype type,
1570 				 enum cxd2880_dvbt2_plp_constell *qam)
1571 {
1572 	u8 data;
1573 	u8 l1_post_ok = 0;
1574 	int ret;
1575 
1576 	if (!tnr_dmd || !qam)
1577 		return -EINVAL;
1578 
1579 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1580 		return -EINVAL;
1581 
1582 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1583 		return -EINVAL;
1584 
1585 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1586 		return -EINVAL;
1587 
1588 	ret = slvt_freeze_reg(tnr_dmd);
1589 	if (ret)
1590 		return ret;
1591 
1592 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1593 				     CXD2880_IO_TGT_DMD,
1594 				     0x00, 0x0b);
1595 	if (ret) {
1596 		slvt_unfreeze_reg(tnr_dmd);
1597 		return ret;
1598 	}
1599 
1600 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1601 				     CXD2880_IO_TGT_DMD,
1602 				     0x86, &l1_post_ok, 1);
1603 	if (ret) {
1604 		slvt_unfreeze_reg(tnr_dmd);
1605 		return ret;
1606 	}
1607 
1608 	if (!(l1_post_ok & 0x01)) {
1609 		slvt_unfreeze_reg(tnr_dmd);
1610 		return -EAGAIN;
1611 	}
1612 
1613 	if (type == CXD2880_DVBT2_PLP_COMMON) {
1614 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1615 					     CXD2880_IO_TGT_DMD,
1616 					     0xb6, &data, 1);
1617 		if (ret) {
1618 			slvt_unfreeze_reg(tnr_dmd);
1619 			return ret;
1620 		}
1621 
1622 		if (data == 0) {
1623 			slvt_unfreeze_reg(tnr_dmd);
1624 			return -EAGAIN;
1625 		}
1626 
1627 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1628 					     CXD2880_IO_TGT_DMD,
1629 					     0xb1, &data, 1);
1630 		if (ret) {
1631 			slvt_unfreeze_reg(tnr_dmd);
1632 			return ret;
1633 		}
1634 	} else {
1635 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1636 					     CXD2880_IO_TGT_DMD,
1637 					     0x9e, &data, 1);
1638 		if (ret) {
1639 			slvt_unfreeze_reg(tnr_dmd);
1640 			return ret;
1641 		}
1642 	}
1643 
1644 	slvt_unfreeze_reg(tnr_dmd);
1645 
1646 	*qam = (enum cxd2880_dvbt2_plp_constell)(data & 0x07);
1647 
1648 	return ret;
1649 }
1650 
1651 int cxd2880_tnrdmd_dvbt2_mon_code_rate(struct cxd2880_tnrdmd
1652 				       *tnr_dmd,
1653 				       enum cxd2880_dvbt2_plp_btype
1654 				       type,
1655 				       enum
1656 				       cxd2880_dvbt2_plp_code_rate
1657 				       *code_rate)
1658 {
1659 	u8 data;
1660 	u8 l1_post_ok = 0;
1661 	int ret;
1662 
1663 	if (!tnr_dmd || !code_rate)
1664 		return -EINVAL;
1665 
1666 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1667 		return -EINVAL;
1668 
1669 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1670 		return -EINVAL;
1671 
1672 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1673 		return -EINVAL;
1674 
1675 	ret = slvt_freeze_reg(tnr_dmd);
1676 	if (ret)
1677 		return ret;
1678 
1679 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1680 				     CXD2880_IO_TGT_DMD,
1681 				     0x00, 0x0b);
1682 	if (ret) {
1683 		slvt_unfreeze_reg(tnr_dmd);
1684 		return ret;
1685 	}
1686 
1687 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1688 				     CXD2880_IO_TGT_DMD,
1689 				     0x86, &l1_post_ok, 1);
1690 	if (ret) {
1691 		slvt_unfreeze_reg(tnr_dmd);
1692 		return ret;
1693 	}
1694 
1695 	if (!(l1_post_ok & 0x01)) {
1696 		slvt_unfreeze_reg(tnr_dmd);
1697 		return -EAGAIN;
1698 	}
1699 
1700 	if (type == CXD2880_DVBT2_PLP_COMMON) {
1701 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1702 					     CXD2880_IO_TGT_DMD,
1703 					     0xb6, &data, 1);
1704 		if (ret) {
1705 			slvt_unfreeze_reg(tnr_dmd);
1706 			return ret;
1707 		}
1708 
1709 		if (data == 0) {
1710 			slvt_unfreeze_reg(tnr_dmd);
1711 			return -EAGAIN;
1712 		}
1713 
1714 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1715 					     CXD2880_IO_TGT_DMD,
1716 					     0xb0, &data, 1);
1717 		if (ret) {
1718 			slvt_unfreeze_reg(tnr_dmd);
1719 			return ret;
1720 		}
1721 	} else {
1722 		ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1723 					     CXD2880_IO_TGT_DMD,
1724 					     0x9d, &data, 1);
1725 		if (ret) {
1726 			slvt_unfreeze_reg(tnr_dmd);
1727 			return ret;
1728 		}
1729 	}
1730 
1731 	slvt_unfreeze_reg(tnr_dmd);
1732 
1733 	*code_rate = (enum cxd2880_dvbt2_plp_code_rate)(data & 0x07);
1734 
1735 	return ret;
1736 }
1737 
1738 int cxd2880_tnrdmd_dvbt2_mon_profile(struct cxd2880_tnrdmd
1739 				     *tnr_dmd,
1740 				     enum cxd2880_dvbt2_profile
1741 				     *profile)
1742 {
1743 	u8 data;
1744 	int ret;
1745 
1746 	if (!tnr_dmd || !profile)
1747 		return -EINVAL;
1748 
1749 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1750 		return -EINVAL;
1751 
1752 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1753 		return -EINVAL;
1754 
1755 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1756 				     CXD2880_IO_TGT_DMD,
1757 				     0x00, 0x0b);
1758 	if (ret)
1759 		return ret;
1760 
1761 	ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1762 				     CXD2880_IO_TGT_DMD,
1763 				     0x22, &data, sizeof(data));
1764 	if (ret)
1765 		return ret;
1766 
1767 	if (data & 0x02) {
1768 		if (data & 0x01)
1769 			*profile = CXD2880_DVBT2_PROFILE_LITE;
1770 		else
1771 			*profile = CXD2880_DVBT2_PROFILE_BASE;
1772 	} else {
1773 		ret = -EAGAIN;
1774 		if (tnr_dmd->diver_mode ==
1775 		    CXD2880_TNRDMD_DIVERMODE_MAIN)
1776 			ret =
1777 			    cxd2880_tnrdmd_dvbt2_mon_profile(tnr_dmd->diver_sub,
1778 							     profile);
1779 
1780 		return ret;
1781 	}
1782 
1783 	return 0;
1784 }
1785 
1786 static int dvbt2_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
1787 			  int rf_lvl, u8 *ssi)
1788 {
1789 	enum cxd2880_dvbt2_plp_constell qam;
1790 	enum cxd2880_dvbt2_plp_code_rate code_rate;
1791 	int prel;
1792 	int temp_ssi = 0;
1793 	int ret;
1794 
1795 	if (!tnr_dmd || !ssi)
1796 		return -EINVAL;
1797 
1798 	ret =
1799 	    cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd, CXD2880_DVBT2_PLP_DATA, &qam);
1800 	if (ret)
1801 		return ret;
1802 
1803 	ret =
1804 	    cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd, CXD2880_DVBT2_PLP_DATA,
1805 					       &code_rate);
1806 	if (ret)
1807 		return ret;
1808 
1809 	if (code_rate > CXD2880_DVBT2_R2_5 || qam > CXD2880_DVBT2_QAM256)
1810 		return -EINVAL;
1811 
1812 	prel = rf_lvl - ref_dbm_1000[qam][code_rate];
1813 
1814 	if (prel < -15000)
1815 		temp_ssi = 0;
1816 	else if (prel < 0)
1817 		temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
1818 	else if (prel < 20000)
1819 		temp_ssi = (((4 * prel) + 500) / 1000) + 10;
1820 	else if (prel < 35000)
1821 		temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
1822 	else
1823 		temp_ssi = 100;
1824 
1825 	*ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
1826 
1827 	return ret;
1828 }
1829 
1830 int cxd2880_tnrdmd_dvbt2_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
1831 				 u8 *ssi)
1832 {
1833 	int rf_lvl = 0;
1834 	int ret;
1835 
1836 	if (!tnr_dmd || !ssi)
1837 		return -EINVAL;
1838 
1839 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1840 		return -EINVAL;
1841 
1842 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1843 		return -EINVAL;
1844 
1845 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1846 		return -EINVAL;
1847 
1848 	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
1849 	if (ret)
1850 		return ret;
1851 
1852 	return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
1853 }
1854 
1855 int cxd2880_tnrdmd_dvbt2_mon_ssi_sub(struct cxd2880_tnrdmd
1856 				     *tnr_dmd, u8 *ssi)
1857 {
1858 	int rf_lvl = 0;
1859 	int ret;
1860 
1861 	if (!tnr_dmd || !ssi)
1862 		return -EINVAL;
1863 
1864 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
1865 		return -EINVAL;
1866 
1867 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1868 		return -EINVAL;
1869 
1870 	if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT2)
1871 		return -EINVAL;
1872 
1873 	ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
1874 	if (ret)
1875 		return ret;
1876 
1877 	return dvbt2_calc_ssi(tnr_dmd, rf_lvl, ssi);
1878 }
1879