• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * cxd2880_tnrdmd_dvbt.c
4  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5  * control functions for DVB-T
6  *
7  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8  */
9 
10 #include <media/dvb_frontend.h>
11 
12 #include "cxd2880_tnrdmd_dvbt.h"
13 #include "cxd2880_tnrdmd_dvbt_mon.h"
14 
15 static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
16 	{0x00, 0x00}, {0x31, 0x01},
17 };
18 
19 static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
20 	{0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03},
21 	{0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25},
22 };
23 
24 static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
25 	{0x00, 0x12}, {0x44, 0x00},
26 };
27 
28 static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
29 	{0x00, 0x11}, {0x87, 0xd2},
30 };
31 
32 static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
33 	{0x00, 0x00}, {0xfd, 0x01},
34 };
35 
36 static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
37 	{0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
38 };
39 
40 static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
41 	{0x00, 0x11}, {0x87, 0x04},
42 };
43 
x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_dtv_bandwidth bandwidth,enum cxd2880_tnrdmd_clockmode clk_mode)44 static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
45 				     *tnr_dmd,
46 				     enum cxd2880_dtv_bandwidth
47 				     bandwidth,
48 				     enum cxd2880_tnrdmd_clockmode
49 				     clk_mode)
50 {
51 	static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 };
52 	static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 };
53 	static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 };
54 	static const u8 ratectl_margin[2] = { 0x01, 0xf0 };
55 	static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 };
56 	static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa };
57 	static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 };
58 
59 	static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00};
60 	static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa};
61 	static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 };
62 	static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 };
63 	static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 };
64 	static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 };
65 	static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 };
66 	static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 };
67 	static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 };
68 
69 	static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00};
70 	static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55};
71 	static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c };
72 	static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 };
73 	static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 };
74 	static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 };
75 	static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa };
76 	static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
77 	static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 };
78 
79 	static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00};
80 	static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38};
81 	static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 };
82 	static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 };
83 	static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c };
84 	static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
85 	static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 };
86 	static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff };
87 	static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 };
88 
89 	static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99};
90 	static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa};
91 	static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d };
92 	static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 };
93 	static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 };
94 	static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 };
95 	static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 };
96 	static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc };
97 	static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 };
98 	const u8 *data = NULL;
99 	u8 sst_data;
100 	int ret;
101 
102 	if (!tnr_dmd)
103 		return -EINVAL;
104 
105 	ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
106 					  CXD2880_IO_TGT_SYS,
107 					  tune_dmd_setting_seq1,
108 					  ARRAY_SIZE(tune_dmd_setting_seq1));
109 	if (ret)
110 		return ret;
111 
112 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
113 				     CXD2880_IO_TGT_DMD,
114 				     0x00, 0x04);
115 	if (ret)
116 		return ret;
117 
118 	switch (clk_mode) {
119 	case CXD2880_TNRDMD_CLOCKMODE_A:
120 		data = clk_mode_ckffrq_a;
121 		break;
122 	case CXD2880_TNRDMD_CLOCKMODE_B:
123 		data = clk_mode_ckffrq_b;
124 		break;
125 	case CXD2880_TNRDMD_CLOCKMODE_C:
126 		data = clk_mode_ckffrq_c;
127 		break;
128 	default:
129 		return -EINVAL;
130 	}
131 
132 	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
133 				      CXD2880_IO_TGT_DMD,
134 				      0x65, data, 2);
135 	if (ret)
136 		return ret;
137 
138 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
139 				     CXD2880_IO_TGT_DMD,
140 				     0x5d, 0x07);
141 	if (ret)
142 		return ret;
143 
144 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
145 		u8 data[2] = { 0x01, 0x01 };
146 
147 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
148 					     CXD2880_IO_TGT_DMD,
149 					     0x00, 0x00);
150 		if (ret)
151 			return ret;
152 
153 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
154 					      CXD2880_IO_TGT_DMD,
155 					      0xce, data, 2);
156 		if (ret)
157 			return ret;
158 	}
159 
160 	ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
161 					  CXD2880_IO_TGT_DMD,
162 					  tune_dmd_setting_seq2,
163 					  ARRAY_SIZE(tune_dmd_setting_seq2));
164 	if (ret)
165 		return ret;
166 
167 	ret = tnr_dmd->io->write_regs(tnr_dmd->io,
168 				      CXD2880_IO_TGT_DMD,
169 				      0xf0, ratectl_margin, 2);
170 	if (ret)
171 		return ret;
172 
173 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN ||
174 	    tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
175 		ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
176 						  CXD2880_IO_TGT_DMD,
177 						  tune_dmd_setting_seq3,
178 						  ARRAY_SIZE(tune_dmd_setting_seq3));
179 		if (ret)
180 			return ret;
181 	}
182 
183 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
184 		ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
185 						  CXD2880_IO_TGT_DMD,
186 						  tune_dmd_setting_seq4,
187 						  ARRAY_SIZE(tune_dmd_setting_seq4));
188 		if (ret)
189 			return ret;
190 	}
191 
192 	if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
193 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
194 					     CXD2880_IO_TGT_DMD,
195 					     0x00, 0x04);
196 		if (ret)
197 			return ret;
198 
199 		switch (clk_mode) {
200 		case CXD2880_TNRDMD_CLOCKMODE_A:
201 			data = maxclkcnt_a;
202 			break;
203 		case CXD2880_TNRDMD_CLOCKMODE_B:
204 			data = maxclkcnt_b;
205 			break;
206 		case CXD2880_TNRDMD_CLOCKMODE_C:
207 			data = maxclkcnt_c;
208 			break;
209 		default:
210 			return -EINVAL;
211 		}
212 
213 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
214 					      CXD2880_IO_TGT_DMD,
215 					      0x68, data, 3);
216 		if (ret)
217 			return ret;
218 	}
219 
220 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
221 				     CXD2880_IO_TGT_DMD,
222 				     0x00, 0x04);
223 	if (ret)
224 		return ret;
225 
226 	switch (bandwidth) {
227 	case CXD2880_DTV_BW_8_MHZ:
228 		switch (clk_mode) {
229 		case CXD2880_TNRDMD_CLOCKMODE_A:
230 		case CXD2880_TNRDMD_CLOCKMODE_C:
231 			data = bw8_nomi_ac;
232 			break;
233 		case CXD2880_TNRDMD_CLOCKMODE_B:
234 			data = bw8_nomi_b;
235 			break;
236 		default:
237 			return -EINVAL;
238 		}
239 
240 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
241 					      CXD2880_IO_TGT_DMD,
242 					      0x60, data, 5);
243 		if (ret)
244 			return ret;
245 
246 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
247 					     CXD2880_IO_TGT_DMD,
248 					     0x4a, 0x00);
249 		if (ret)
250 			return ret;
251 
252 		switch (clk_mode) {
253 		case CXD2880_TNRDMD_CLOCKMODE_A:
254 			data = bw8_gtdofst_a;
255 			break;
256 		case CXD2880_TNRDMD_CLOCKMODE_B:
257 			data = bw8_gtdofst_b;
258 			break;
259 		case CXD2880_TNRDMD_CLOCKMODE_C:
260 			data = bw8_gtdofst_c;
261 			break;
262 		default:
263 			return -EINVAL;
264 		}
265 
266 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
267 					      CXD2880_IO_TGT_DMD,
268 					      0x7d, data, 2);
269 		if (ret)
270 			return ret;
271 
272 		switch (clk_mode) {
273 		case CXD2880_TNRDMD_CLOCKMODE_A:
274 		case CXD2880_TNRDMD_CLOCKMODE_B:
275 			sst_data = 0x35;
276 			break;
277 		case CXD2880_TNRDMD_CLOCKMODE_C:
278 			sst_data = 0x34;
279 			break;
280 		default:
281 			return -EINVAL;
282 		}
283 
284 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
285 					     CXD2880_IO_TGT_DMD,
286 					     0x71, sst_data);
287 		if (ret)
288 			return ret;
289 
290 		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
291 			switch (clk_mode) {
292 			case CXD2880_TNRDMD_CLOCKMODE_A:
293 				data = bw8_mrc_a;
294 				break;
295 			case CXD2880_TNRDMD_CLOCKMODE_B:
296 				data = bw8_mrc_b;
297 				break;
298 			case CXD2880_TNRDMD_CLOCKMODE_C:
299 				data = bw8_mrc_c;
300 				break;
301 			default:
302 				return -EINVAL;
303 			}
304 
305 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
306 						      CXD2880_IO_TGT_DMD,
307 						      0x4b, &data[0], 2);
308 			if (ret)
309 				return ret;
310 
311 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
312 						      CXD2880_IO_TGT_DMD,
313 						      0x51, &data[2], 3);
314 			if (ret)
315 				return ret;
316 		}
317 
318 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
319 					      CXD2880_IO_TGT_DMD,
320 					      0x72, &bw8_notch[0], 2);
321 		if (ret)
322 			return ret;
323 
324 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
325 					      CXD2880_IO_TGT_DMD,
326 					      0x6b, &bw8_notch[2], 2);
327 		if (ret)
328 			return ret;
329 		break;
330 
331 	case CXD2880_DTV_BW_7_MHZ:
332 		switch (clk_mode) {
333 		case CXD2880_TNRDMD_CLOCKMODE_A:
334 		case CXD2880_TNRDMD_CLOCKMODE_C:
335 			data = bw7_nomi_ac;
336 			break;
337 		case CXD2880_TNRDMD_CLOCKMODE_B:
338 			data = bw7_nomi_b;
339 			break;
340 		default:
341 			return -EINVAL;
342 		}
343 
344 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
345 					      CXD2880_IO_TGT_DMD,
346 					      0x60, data, 5);
347 		if (ret)
348 			return ret;
349 
350 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
351 					     CXD2880_IO_TGT_DMD,
352 					     0x4a, 0x02);
353 		if (ret)
354 			return ret;
355 
356 		switch (clk_mode) {
357 		case CXD2880_TNRDMD_CLOCKMODE_A:
358 			data = bw7_gtdofst_a;
359 			break;
360 		case CXD2880_TNRDMD_CLOCKMODE_B:
361 			data = bw7_gtdofst_b;
362 			break;
363 		case CXD2880_TNRDMD_CLOCKMODE_C:
364 			data = bw7_gtdofst_c;
365 			break;
366 		default:
367 			return -EINVAL;
368 		}
369 
370 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
371 					      CXD2880_IO_TGT_DMD,
372 					      0x7d, data, 2);
373 		if (ret)
374 			return ret;
375 
376 		switch (clk_mode) {
377 		case CXD2880_TNRDMD_CLOCKMODE_A:
378 		case CXD2880_TNRDMD_CLOCKMODE_B:
379 			sst_data = 0x2f;
380 			break;
381 		case CXD2880_TNRDMD_CLOCKMODE_C:
382 			sst_data = 0x2e;
383 			break;
384 		default:
385 			return -EINVAL;
386 		}
387 
388 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
389 					     CXD2880_IO_TGT_DMD,
390 					     0x71, sst_data);
391 		if (ret)
392 			return ret;
393 
394 		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
395 			switch (clk_mode) {
396 			case CXD2880_TNRDMD_CLOCKMODE_A:
397 				data = bw7_mrc_a;
398 				break;
399 			case CXD2880_TNRDMD_CLOCKMODE_B:
400 				data = bw7_mrc_b;
401 				break;
402 			case CXD2880_TNRDMD_CLOCKMODE_C:
403 				data = bw7_mrc_c;
404 				break;
405 			default:
406 				return -EINVAL;
407 			}
408 
409 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
410 						      CXD2880_IO_TGT_DMD,
411 						      0x4b, &data[0], 2);
412 			if (ret)
413 				return ret;
414 
415 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
416 						      CXD2880_IO_TGT_DMD,
417 						      0x51, &data[2], 3);
418 			if (ret)
419 				return ret;
420 		}
421 
422 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
423 					      CXD2880_IO_TGT_DMD,
424 					      0x72, &bw7_notch[0], 2);
425 		if (ret)
426 			return ret;
427 
428 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
429 					      CXD2880_IO_TGT_DMD,
430 					      0x6b, &bw7_notch[2], 2);
431 		if (ret)
432 			return ret;
433 		break;
434 
435 	case CXD2880_DTV_BW_6_MHZ:
436 		switch (clk_mode) {
437 		case CXD2880_TNRDMD_CLOCKMODE_A:
438 		case CXD2880_TNRDMD_CLOCKMODE_C:
439 			data = bw6_nomi_ac;
440 			break;
441 		case CXD2880_TNRDMD_CLOCKMODE_B:
442 			data = bw6_nomi_b;
443 			break;
444 		default:
445 			return -EINVAL;
446 		}
447 
448 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
449 					      CXD2880_IO_TGT_DMD,
450 					      0x60, data, 5);
451 		if (ret)
452 			return ret;
453 
454 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
455 					     CXD2880_IO_TGT_DMD,
456 					     0x4a, 0x04);
457 		if (ret)
458 			return ret;
459 
460 		switch (clk_mode) {
461 		case CXD2880_TNRDMD_CLOCKMODE_A:
462 			data = bw6_gtdofst_a;
463 			break;
464 		case CXD2880_TNRDMD_CLOCKMODE_B:
465 			data = bw6_gtdofst_b;
466 			break;
467 		case CXD2880_TNRDMD_CLOCKMODE_C:
468 			data = bw6_gtdofst_c;
469 			break;
470 		default:
471 			return -EINVAL;
472 		}
473 
474 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
475 					      CXD2880_IO_TGT_DMD,
476 					      0x7d, data, 2);
477 		if (ret)
478 			return ret;
479 
480 		switch (clk_mode) {
481 		case CXD2880_TNRDMD_CLOCKMODE_A:
482 		case CXD2880_TNRDMD_CLOCKMODE_C:
483 			sst_data = 0x29;
484 			break;
485 		case CXD2880_TNRDMD_CLOCKMODE_B:
486 			sst_data = 0x2a;
487 			break;
488 		default:
489 			return -EINVAL;
490 		}
491 
492 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
493 					     CXD2880_IO_TGT_DMD,
494 					     0x71, sst_data);
495 		if (ret)
496 			return ret;
497 
498 		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
499 			switch (clk_mode) {
500 			case CXD2880_TNRDMD_CLOCKMODE_A:
501 				data = bw6_mrc_a;
502 				break;
503 			case CXD2880_TNRDMD_CLOCKMODE_B:
504 				data = bw6_mrc_b;
505 				break;
506 			case CXD2880_TNRDMD_CLOCKMODE_C:
507 				data = bw6_mrc_c;
508 				break;
509 			default:
510 				return -EINVAL;
511 			}
512 
513 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
514 						      CXD2880_IO_TGT_DMD,
515 						      0x4b, &data[0], 2);
516 			if (ret)
517 				return ret;
518 
519 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
520 						      CXD2880_IO_TGT_DMD,
521 						      0x51, &data[2], 3);
522 			if (ret)
523 				return ret;
524 		}
525 
526 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
527 					      CXD2880_IO_TGT_DMD,
528 					      0x72, &bw6_notch[0], 2);
529 		if (ret)
530 			return ret;
531 
532 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
533 					      CXD2880_IO_TGT_DMD,
534 					      0x6b, &bw6_notch[2], 2);
535 		if (ret)
536 			return ret;
537 		break;
538 
539 	case CXD2880_DTV_BW_5_MHZ:
540 		switch (clk_mode) {
541 		case CXD2880_TNRDMD_CLOCKMODE_A:
542 		case CXD2880_TNRDMD_CLOCKMODE_C:
543 			data = bw5_nomi_ac;
544 			break;
545 		case CXD2880_TNRDMD_CLOCKMODE_B:
546 			data = bw5_nomi_b;
547 			break;
548 		default:
549 			return -EINVAL;
550 		}
551 
552 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
553 					      CXD2880_IO_TGT_DMD,
554 					      0x60, data, 5);
555 		if (ret)
556 			return ret;
557 
558 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
559 					     CXD2880_IO_TGT_DMD,
560 					     0x4a, 0x06);
561 		if (ret)
562 			return ret;
563 
564 		switch (clk_mode) {
565 		case CXD2880_TNRDMD_CLOCKMODE_A:
566 			data = bw5_gtdofst_a;
567 			break;
568 		case CXD2880_TNRDMD_CLOCKMODE_B:
569 			data = bw5_gtdofst_b;
570 			break;
571 		case CXD2880_TNRDMD_CLOCKMODE_C:
572 			data = bw5_gtdofst_c;
573 			break;
574 		default:
575 			return -EINVAL;
576 		}
577 
578 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
579 					      CXD2880_IO_TGT_DMD,
580 					      0x7d, data, 2);
581 		if (ret)
582 			return ret;
583 
584 		switch (clk_mode) {
585 		case CXD2880_TNRDMD_CLOCKMODE_A:
586 		case CXD2880_TNRDMD_CLOCKMODE_B:
587 			sst_data = 0x24;
588 			break;
589 		case CXD2880_TNRDMD_CLOCKMODE_C:
590 			sst_data = 0x23;
591 			break;
592 		default:
593 			return -EINVAL;
594 		}
595 
596 		ret = tnr_dmd->io->write_reg(tnr_dmd->io,
597 					     CXD2880_IO_TGT_DMD,
598 					     0x71, sst_data);
599 		if (ret)
600 			return ret;
601 
602 		if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
603 			switch (clk_mode) {
604 			case CXD2880_TNRDMD_CLOCKMODE_A:
605 				data = bw5_mrc_a;
606 				break;
607 			case CXD2880_TNRDMD_CLOCKMODE_B:
608 				data = bw5_mrc_b;
609 				break;
610 			case CXD2880_TNRDMD_CLOCKMODE_C:
611 				data = bw5_mrc_c;
612 				break;
613 			default:
614 				return -EINVAL;
615 			}
616 
617 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
618 						      CXD2880_IO_TGT_DMD,
619 						      0x4b, &data[0], 2);
620 			if (ret)
621 				return ret;
622 
623 			ret = tnr_dmd->io->write_regs(tnr_dmd->io,
624 						      CXD2880_IO_TGT_DMD,
625 						      0x51, &data[2], 3);
626 			if (ret)
627 				return ret;
628 		}
629 
630 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
631 					      CXD2880_IO_TGT_DMD,
632 					      0x72, &bw5_notch[0], 2);
633 		if (ret)
634 			return ret;
635 
636 		ret = tnr_dmd->io->write_regs(tnr_dmd->io,
637 					      CXD2880_IO_TGT_DMD,
638 					      0x6b, &bw5_notch[2], 2);
639 		if (ret)
640 			return ret;
641 		break;
642 
643 	default:
644 		return -EINVAL;
645 	}
646 
647 	return cxd2880_io_write_multi_regs(tnr_dmd->io,
648 					   CXD2880_IO_TGT_DMD,
649 					   tune_dmd_setting_seq5,
650 					   ARRAY_SIZE(tune_dmd_setting_seq5));
651 }
652 
x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd * tnr_dmd)653 static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
654 						   *tnr_dmd)
655 {
656 	int ret;
657 
658 	if (!tnr_dmd)
659 		return -EINVAL;
660 
661 	ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
662 					  CXD2880_IO_TGT_DMD,
663 					  sleep_dmd_setting_seq1,
664 					  ARRAY_SIZE(sleep_dmd_setting_seq1));
665 	if (ret)
666 		return ret;
667 
668 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
669 		ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
670 						  CXD2880_IO_TGT_DMD,
671 						  sleep_dmd_setting_seq2,
672 						  ARRAY_SIZE(sleep_dmd_setting_seq2));
673 
674 	return ret;
675 }
676 
dvbt_set_profile(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_dvbt_profile profile)677 static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
678 			    enum cxd2880_dvbt_profile profile)
679 {
680 	int ret;
681 
682 	if (!tnr_dmd)
683 		return -EINVAL;
684 
685 	ret = tnr_dmd->io->write_reg(tnr_dmd->io,
686 				     CXD2880_IO_TGT_DMD,
687 				     0x00, 0x10);
688 	if (ret)
689 		return ret;
690 
691 	return tnr_dmd->io->write_reg(tnr_dmd->io,
692 				      CXD2880_IO_TGT_DMD,
693 				      0x67,
694 				      (profile == CXD2880_DVBT_PROFILE_HP)
695 				      ? 0x00 : 0x01);
696 }
697 
cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd * tnr_dmd,struct cxd2880_dvbt_tune_param * tune_param)698 int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
699 			      struct cxd2880_dvbt_tune_param
700 			      *tune_param)
701 {
702 	int ret;
703 
704 	if (!tnr_dmd || !tune_param)
705 		return -EINVAL;
706 
707 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
708 		return -EINVAL;
709 
710 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
711 	    tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
712 		return -EINVAL;
713 
714 	ret =
715 	    cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
716 						tune_param->center_freq_khz,
717 						tune_param->bandwidth, 0, 0);
718 	if (ret)
719 		return ret;
720 
721 	ret =
722 	    x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
723 				      tnr_dmd->clk_mode);
724 	if (ret)
725 		return ret;
726 
727 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
728 		ret =
729 		    x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
730 					      tune_param->bandwidth,
731 					      tnr_dmd->diver_sub->clk_mode);
732 		if (ret)
733 			return ret;
734 	}
735 
736 	return dvbt_set_profile(tnr_dmd, tune_param->profile);
737 }
738 
cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd * tnr_dmd,struct cxd2880_dvbt_tune_param * tune_param)739 int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
740 			      struct cxd2880_dvbt_tune_param
741 			      *tune_param)
742 {
743 	int ret;
744 
745 	if (!tnr_dmd || !tune_param)
746 		return -EINVAL;
747 
748 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
749 		return -EINVAL;
750 
751 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
752 	    tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
753 		return -EINVAL;
754 
755 	ret =
756 	    cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
757 						0);
758 	if (ret)
759 		return ret;
760 
761 	tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
762 	tnr_dmd->frequency_khz = tune_param->center_freq_khz;
763 	tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
764 	tnr_dmd->bandwidth = tune_param->bandwidth;
765 
766 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
767 		tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
768 		tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
769 		tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
770 		tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
771 	}
772 
773 	return 0;
774 }
775 
cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd * tnr_dmd)776 int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
777 {
778 	int ret;
779 
780 	if (!tnr_dmd)
781 		return -EINVAL;
782 
783 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
784 		return -EINVAL;
785 
786 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
787 	    tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
788 		return -EINVAL;
789 
790 	ret = x_sleep_dvbt_demod_setting(tnr_dmd);
791 	if (ret)
792 		return ret;
793 
794 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
795 		ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
796 
797 	return ret;
798 }
799 
cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_tnrdmd_lock_result * lock)800 int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
801 					 *tnr_dmd,
802 					 enum
803 					 cxd2880_tnrdmd_lock_result
804 					 *lock)
805 {
806 	int ret;
807 
808 	u8 sync_stat = 0;
809 	u8 ts_lock = 0;
810 	u8 unlock_detected = 0;
811 	u8 unlock_detected_sub = 0;
812 
813 	if (!tnr_dmd || !lock)
814 		return -EINVAL;
815 
816 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
817 		return -EINVAL;
818 
819 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
820 		return -EINVAL;
821 
822 	ret =
823 	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
824 					      &unlock_detected);
825 	if (ret)
826 		return ret;
827 
828 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
829 		if (sync_stat == 6)
830 			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
831 		else if (unlock_detected)
832 			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
833 		else
834 			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
835 
836 		return 0;
837 	}
838 
839 	if (sync_stat == 6) {
840 		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
841 		return 0;
842 	}
843 
844 	ret =
845 	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
846 						  &unlock_detected_sub);
847 	if (ret)
848 		return ret;
849 
850 	if (sync_stat == 6)
851 		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
852 	else if (unlock_detected && unlock_detected_sub)
853 		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
854 	else
855 		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
856 
857 	return 0;
858 }
859 
cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_tnrdmd_lock_result * lock)860 int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
861 				      *tnr_dmd,
862 				      enum
863 				      cxd2880_tnrdmd_lock_result
864 				      *lock)
865 {
866 	int ret;
867 
868 	u8 sync_stat = 0;
869 	u8 ts_lock = 0;
870 	u8 unlock_detected = 0;
871 	u8 unlock_detected_sub = 0;
872 
873 	if (!tnr_dmd || !lock)
874 		return -EINVAL;
875 
876 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
877 		return -EINVAL;
878 
879 	if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
880 		return -EINVAL;
881 
882 	ret =
883 	    cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
884 					      &unlock_detected);
885 	if (ret)
886 		return ret;
887 
888 	if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
889 		if (ts_lock)
890 			*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
891 		else if (unlock_detected)
892 			*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
893 		else
894 			*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
895 
896 		return 0;
897 	}
898 
899 	if (ts_lock) {
900 		*lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
901 		return 0;
902 	} else if (!unlock_detected) {
903 		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
904 		return 0;
905 	}
906 
907 	ret =
908 	    cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
909 						  &unlock_detected_sub);
910 	if (ret)
911 		return ret;
912 
913 	if (unlock_detected && unlock_detected_sub)
914 		*lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
915 	else
916 		*lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
917 
918 	return 0;
919 }
920