1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * cxd2880_tnrdmd_dvbt2.c
4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver
5 * control functions for DVB-T2
6 *
7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
8 */
9
10 #include <media/dvb_frontend.h>
11
12 #include "cxd2880_tnrdmd_dvbt2.h"
13 #include "cxd2880_tnrdmd_dvbt2_mon.h"
14
15 static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
16 {0x00, 0x00}, {0x31, 0x02},
17 };
18
19 static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
20 {0x00, 0x04}, {0x5d, 0x0b},
21 };
22
x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_dtv_bandwidth bandwidth,enum cxd2880_tnrdmd_clockmode clk_mode)23 static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd
24 *tnr_dmd,
25 enum cxd2880_dtv_bandwidth
26 bandwidth,
27 enum cxd2880_tnrdmd_clockmode
28 clk_mode)
29 {
30 static const u8 tsif_settings[2] = { 0x01, 0x01 };
31 static const u8 init_settings[14] = {
32 0x07, 0x06, 0x01, 0xf0, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00,
33 0x09, 0x9c, 0x0e, 0x4c
34 };
35 static const u8 clk_mode_settings_a1[9] = {
36 0x52, 0x49, 0x2c, 0x51, 0x51, 0x3d, 0x15, 0x29, 0x0c
37 };
38
39 static const u8 clk_mode_settings_b1[9] = {
40 0x5d, 0x55, 0x32, 0x5c, 0x5c, 0x45, 0x17, 0x2e, 0x0d
41 };
42
43 static const u8 clk_mode_settings_c1[9] = {
44 0x60, 0x00, 0x34, 0x5e, 0x5e, 0x47, 0x18, 0x2f, 0x0e
45 };
46
47 static const u8 clk_mode_settings_a2[13] = {
48 0x04, 0xe7, 0x94, 0x92, 0x09, 0xcf, 0x7e, 0xd0, 0x49,
49 0xcd, 0xcd, 0x1f, 0x5b
50 };
51
52 static const u8 clk_mode_settings_b2[13] = {
53 0x05, 0x90, 0x27, 0x55, 0x0b, 0x20, 0x8f, 0xd6, 0xea,
54 0xc8, 0xc8, 0x23, 0x91
55 };
56
57 static const u8 clk_mode_settings_c2[13] = {
58 0x05, 0xb8, 0xd8, 0x00, 0x0b, 0x72, 0x93, 0xf3, 0x00,
59 0xcd, 0xcd, 0x24, 0x95
60 };
61
62 static const u8 clk_mode_settings_a3[5] = {
63 0x0b, 0x6a, 0xc9, 0x03, 0x33
64 };
65 static const u8 clk_mode_settings_b3[5] = {
66 0x01, 0x02, 0xe4, 0x03, 0x39
67 };
68 static const u8 clk_mode_settings_c3[5] = {
69 0x01, 0x02, 0xeb, 0x03, 0x3b
70 };
71
72 static const u8 gtdofst[2] = { 0x3f, 0xff };
73
74 static const u8 bw8_gtdofst_a[2] = { 0x19, 0xd2 };
75 static const u8 bw8_nomi_ac[6] = { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 };
76 static const u8 bw8_nomi_b[6] = { 0x14, 0x6a, 0xaa, 0xaa, 0xab, 0x00 };
77 static const u8 bw8_sst_a[2] = { 0x06, 0x2a };
78 static const u8 bw8_sst_b[2] = { 0x06, 0x29 };
79 static const u8 bw8_sst_c[2] = { 0x06, 0x28 };
80 static const u8 bw8_mrc_a[9] = {
81 0x28, 0x00, 0x50, 0x00, 0x60, 0x00, 0x00, 0x90, 0x00
82 };
83 static const u8 bw8_mrc_b[9] = {
84 0x2d, 0x5e, 0x5a, 0xbd, 0x6c, 0xe3, 0x00, 0xa3, 0x55
85 };
86 static const u8 bw8_mrc_c[9] = {
87 0x2e, 0xaa, 0x5d, 0x55, 0x70, 0x00, 0x00, 0xa8, 0x00
88 };
89
90 static const u8 bw7_nomi_ac[6] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 };
91 static const u8 bw7_nomi_b[6] = { 0x17, 0x55, 0x55, 0x55, 0x55, 0x00 };
92 static const u8 bw7_sst_a[2] = { 0x06, 0x23 };
93 static const u8 bw7_sst_b[2] = { 0x06, 0x22 };
94 static const u8 bw7_sst_c[2] = { 0x06, 0x21 };
95 static const u8 bw7_mrc_a[9] = {
96 0x2d, 0xb6, 0x5b, 0x6d, 0x6d, 0xb6, 0x00, 0xa4, 0x92
97 };
98 static const u8 bw7_mrc_b[9] = {
99 0x33, 0xda, 0x67, 0xb4, 0x7c, 0x71, 0x00, 0xba, 0xaa
100 };
101 static const u8 bw7_mrc_c[9] = {
102 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00
103 };
104
105 static const u8 bw6_nomi_ac[6] = { 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 };
106 static const u8 bw6_nomi_b[6] = { 0x1b, 0x38, 0xe3, 0x8e, 0x39, 0x00 };
107 static const u8 bw6_sst_a[2] = { 0x06, 0x1c };
108 static const u8 bw6_sst_b[2] = { 0x06, 0x1b };
109 static const u8 bw6_sst_c[2] = { 0x06, 0x1a };
110 static const u8 bw6_mrc_a[9] = {
111 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00
112 };
113 static const u8 bw6_mrc_b[9] = {
114 0x3c, 0x7e, 0x78, 0xfc, 0x91, 0x2f, 0x00, 0xd9, 0xc7
115 };
116 static const u8 bw6_mrc_c[9] = {
117 0x3e, 0x38, 0x7c, 0x71, 0x95, 0x55, 0x00, 0xdf, 0xff
118 };
119
120 static const u8 bw5_nomi_ac[6] = { 0x21, 0x99, 0x99, 0x99, 0x9a, 0x00 };
121 static const u8 bw5_nomi_b[6] = { 0x20, 0xaa, 0xaa, 0xaa, 0xab, 0x00 };
122 static const u8 bw5_sst_a[2] = { 0x06, 0x15 };
123 static const u8 bw5_sst_b[2] = { 0x06, 0x15 };
124 static const u8 bw5_sst_c[2] = { 0x06, 0x14 };
125 static const u8 bw5_mrc_a[9] = {
126 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xe6, 0x66
127 };
128 static const u8 bw5_mrc_b[9] = {
129 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x01, 0x05, 0x55
130 };
131 static const u8 bw5_mrc_c[9] = {
132 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x01, 0x0c, 0xcc
133 };
134
135 static const u8 bw1_7_nomi_a[6] = {
136 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03
137 };
138 static const u8 bw1_7_nomi_c[6] = {
139 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03
140 };
141 static const u8 bw1_7_nomi_b[6] = {
142 0x65, 0x2b, 0xa4, 0xcd, 0xd8, 0x03
143 };
144 static const u8 bw1_7_sst_a[2] = { 0x06, 0x0c };
145 static const u8 bw1_7_sst_b[2] = { 0x06, 0x0c };
146 static const u8 bw1_7_sst_c[2] = { 0x06, 0x0b };
147 static const u8 bw1_7_mrc_a[9] = {
148 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x02, 0xc9, 0x8f
149 };
150 static const u8 bw1_7_mrc_b[9] = {
151 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x03, 0x29, 0x5d
152 };
153 static const u8 bw1_7_mrc_c[9] = {
154 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x03, 0x40, 0x7d
155 };
156
157 const u8 *data = NULL;
158 const u8 *data2 = NULL;
159 const u8 *data3 = NULL;
160 int ret;
161
162 if (!tnr_dmd)
163 return -EINVAL;
164
165 ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
166 CXD2880_IO_TGT_SYS,
167 tune_dmd_setting_seq1,
168 ARRAY_SIZE(tune_dmd_setting_seq1));
169 if (ret)
170 return ret;
171
172 ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
173 CXD2880_IO_TGT_DMD,
174 tune_dmd_setting_seq2,
175 ARRAY_SIZE(tune_dmd_setting_seq2));
176 if (ret)
177 return ret;
178
179 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
180 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
181 CXD2880_IO_TGT_DMD,
182 0x00, 0x00);
183 if (ret)
184 return ret;
185
186 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
187 CXD2880_IO_TGT_DMD,
188 0xce, tsif_settings, 2);
189 if (ret)
190 return ret;
191 }
192
193 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
194 CXD2880_IO_TGT_DMD,
195 0x00, 0x20);
196 if (ret)
197 return ret;
198
199 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
200 CXD2880_IO_TGT_DMD,
201 0x8a, init_settings[0]);
202 if (ret)
203 return ret;
204
205 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
206 CXD2880_IO_TGT_DMD,
207 0x90, init_settings[1]);
208 if (ret)
209 return ret;
210
211 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
212 CXD2880_IO_TGT_DMD,
213 0x00, 0x25);
214 if (ret)
215 return ret;
216
217 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
218 CXD2880_IO_TGT_DMD,
219 0xf0, &init_settings[2], 2);
220 if (ret)
221 return ret;
222
223 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
224 CXD2880_IO_TGT_DMD,
225 0x00, 0x2a);
226 if (ret)
227 return ret;
228
229 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
230 CXD2880_IO_TGT_DMD,
231 0xdc, init_settings[4]);
232 if (ret)
233 return ret;
234
235 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
236 CXD2880_IO_TGT_DMD,
237 0xde, init_settings[5]);
238 if (ret)
239 return ret;
240
241 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
242 CXD2880_IO_TGT_DMD,
243 0x00, 0x2d);
244 if (ret)
245 return ret;
246
247 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
248 CXD2880_IO_TGT_DMD,
249 0x73, &init_settings[6], 4);
250 if (ret)
251 return ret;
252
253 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
254 CXD2880_IO_TGT_DMD,
255 0x8f, &init_settings[10], 4);
256 if (ret)
257 return ret;
258
259 switch (clk_mode) {
260 case CXD2880_TNRDMD_CLOCKMODE_A:
261 data = clk_mode_settings_a1;
262 data2 = clk_mode_settings_a2;
263 data3 = clk_mode_settings_a3;
264 break;
265 case CXD2880_TNRDMD_CLOCKMODE_B:
266 data = clk_mode_settings_b1;
267 data2 = clk_mode_settings_b2;
268 data3 = clk_mode_settings_b3;
269 break;
270 case CXD2880_TNRDMD_CLOCKMODE_C:
271 data = clk_mode_settings_c1;
272 data2 = clk_mode_settings_c2;
273 data3 = clk_mode_settings_c3;
274 break;
275 default:
276 return -EINVAL;
277 }
278
279 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
280 CXD2880_IO_TGT_DMD,
281 0x00, 0x04);
282 if (ret)
283 return ret;
284
285 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
286 CXD2880_IO_TGT_DMD,
287 0x1d, &data[0], 3);
288 if (ret)
289 return ret;
290
291 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
292 CXD2880_IO_TGT_DMD,
293 0x22, data[3]);
294 if (ret)
295 return ret;
296
297 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
298 CXD2880_IO_TGT_DMD,
299 0x24, data[4]);
300 if (ret)
301 return ret;
302
303 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
304 CXD2880_IO_TGT_DMD,
305 0x26, data[5]);
306 if (ret)
307 return ret;
308
309 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
310 CXD2880_IO_TGT_DMD,
311 0x29, &data[6], 2);
312 if (ret)
313 return ret;
314
315 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
316 CXD2880_IO_TGT_DMD,
317 0x2d, data[8]);
318 if (ret)
319 return ret;
320
321 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
322 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
323 CXD2880_IO_TGT_DMD,
324 0x2e, &data2[0], 6);
325 if (ret)
326 return ret;
327
328 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
329 CXD2880_IO_TGT_DMD,
330 0x35, &data2[6], 7);
331 if (ret)
332 return ret;
333 }
334
335 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
336 CXD2880_IO_TGT_DMD,
337 0x3c, &data3[0], 2);
338 if (ret)
339 return ret;
340
341 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
342 CXD2880_IO_TGT_DMD,
343 0x56, &data3[2], 3);
344 if (ret)
345 return ret;
346
347 switch (bandwidth) {
348 case CXD2880_DTV_BW_8_MHZ:
349 switch (clk_mode) {
350 case CXD2880_TNRDMD_CLOCKMODE_A:
351 case CXD2880_TNRDMD_CLOCKMODE_C:
352 data = bw8_nomi_ac;
353 break;
354 case CXD2880_TNRDMD_CLOCKMODE_B:
355 data = bw8_nomi_b;
356 break;
357 default:
358 return -EINVAL;
359 }
360
361 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
362 CXD2880_IO_TGT_DMD,
363 0x10, data, 6);
364 if (ret)
365 return ret;
366
367 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
368 CXD2880_IO_TGT_DMD,
369 0x4a, 0x00);
370 if (ret)
371 return ret;
372
373 switch (clk_mode) {
374 case CXD2880_TNRDMD_CLOCKMODE_A:
375 data = bw8_gtdofst_a;
376 break;
377 case CXD2880_TNRDMD_CLOCKMODE_B:
378 case CXD2880_TNRDMD_CLOCKMODE_C:
379 data = gtdofst;
380 break;
381 default:
382 return -EINVAL;
383 }
384
385 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
386 CXD2880_IO_TGT_DMD,
387 0x19, data, 2);
388 if (ret)
389 return ret;
390
391 switch (clk_mode) {
392 case CXD2880_TNRDMD_CLOCKMODE_A:
393 data = bw8_sst_a;
394 break;
395 case CXD2880_TNRDMD_CLOCKMODE_B:
396 data = bw8_sst_b;
397 break;
398 case CXD2880_TNRDMD_CLOCKMODE_C:
399 data = bw8_sst_c;
400 break;
401 default:
402 return -EINVAL;
403 }
404
405 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
406 CXD2880_IO_TGT_DMD,
407 0x1b, data, 2);
408 if (ret)
409 return ret;
410
411 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
412 switch (clk_mode) {
413 case CXD2880_TNRDMD_CLOCKMODE_A:
414 data = bw8_mrc_a;
415 break;
416 case CXD2880_TNRDMD_CLOCKMODE_B:
417 data = bw8_mrc_b;
418 break;
419 case CXD2880_TNRDMD_CLOCKMODE_C:
420 data = bw8_mrc_c;
421 break;
422 default:
423 return -EINVAL;
424 }
425
426 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
427 CXD2880_IO_TGT_DMD,
428 0x4b, data, 9);
429 if (ret)
430 return ret;
431 }
432 break;
433
434 case CXD2880_DTV_BW_7_MHZ:
435 switch (clk_mode) {
436 case CXD2880_TNRDMD_CLOCKMODE_A:
437 case CXD2880_TNRDMD_CLOCKMODE_C:
438 data = bw7_nomi_ac;
439 break;
440 case CXD2880_TNRDMD_CLOCKMODE_B:
441 data = bw7_nomi_b;
442 break;
443 default:
444 return -EINVAL;
445 }
446
447 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
448 CXD2880_IO_TGT_DMD,
449 0x10, data, 6);
450 if (ret)
451 return ret;
452
453 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
454 CXD2880_IO_TGT_DMD,
455 0x4a, 0x02);
456 if (ret)
457 return ret;
458
459 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
460 CXD2880_IO_TGT_DMD,
461 0x19, gtdofst, 2);
462 if (ret)
463 return ret;
464
465 switch (clk_mode) {
466 case CXD2880_TNRDMD_CLOCKMODE_A:
467 data = bw7_sst_a;
468 break;
469 case CXD2880_TNRDMD_CLOCKMODE_B:
470 data = bw7_sst_b;
471 break;
472 case CXD2880_TNRDMD_CLOCKMODE_C:
473 data = bw7_sst_c;
474 break;
475 default:
476 return -EINVAL;
477 }
478
479 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
480 CXD2880_IO_TGT_DMD,
481 0x1b, data, 2);
482 if (ret)
483 return ret;
484
485 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
486 switch (clk_mode) {
487 case CXD2880_TNRDMD_CLOCKMODE_A:
488 data = bw7_mrc_a;
489 break;
490 case CXD2880_TNRDMD_CLOCKMODE_B:
491 data = bw7_mrc_b;
492 break;
493 case CXD2880_TNRDMD_CLOCKMODE_C:
494 data = bw7_mrc_c;
495 break;
496 default:
497 return -EINVAL;
498 }
499
500 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
501 CXD2880_IO_TGT_DMD,
502 0x4b, data, 9);
503 if (ret)
504 return ret;
505 }
506 break;
507
508 case CXD2880_DTV_BW_6_MHZ:
509 switch (clk_mode) {
510 case CXD2880_TNRDMD_CLOCKMODE_A:
511 case CXD2880_TNRDMD_CLOCKMODE_C:
512 data = bw6_nomi_ac;
513 break;
514 case CXD2880_TNRDMD_CLOCKMODE_B:
515 data = bw6_nomi_b;
516 break;
517 default:
518 return -EINVAL;
519 }
520
521 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
522 CXD2880_IO_TGT_DMD,
523 0x10, data, 6);
524 if (ret)
525 return ret;
526
527 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
528 CXD2880_IO_TGT_DMD,
529 0x4a, 0x04);
530 if (ret)
531 return ret;
532
533 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
534 CXD2880_IO_TGT_DMD,
535 0x19, gtdofst, 2);
536 if (ret)
537 return ret;
538
539 switch (clk_mode) {
540 case CXD2880_TNRDMD_CLOCKMODE_A:
541 data = bw6_sst_a;
542 break;
543 case CXD2880_TNRDMD_CLOCKMODE_B:
544 data = bw6_sst_b;
545 break;
546 case CXD2880_TNRDMD_CLOCKMODE_C:
547 data = bw6_sst_c;
548 break;
549 default:
550 return -EINVAL;
551 }
552
553 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
554 CXD2880_IO_TGT_DMD,
555 0x1b, data, 2);
556 if (ret)
557 return ret;
558
559 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
560 switch (clk_mode) {
561 case CXD2880_TNRDMD_CLOCKMODE_A:
562 data = bw6_mrc_a;
563 break;
564 case CXD2880_TNRDMD_CLOCKMODE_B:
565 data = bw6_mrc_b;
566 break;
567 case CXD2880_TNRDMD_CLOCKMODE_C:
568 data = bw6_mrc_c;
569 break;
570 default:
571 return -EINVAL;
572 }
573
574 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
575 CXD2880_IO_TGT_DMD,
576 0x4b, data, 9);
577 if (ret)
578 return ret;
579 }
580 break;
581
582 case CXD2880_DTV_BW_5_MHZ:
583 switch (clk_mode) {
584 case CXD2880_TNRDMD_CLOCKMODE_A:
585 case CXD2880_TNRDMD_CLOCKMODE_C:
586 data = bw5_nomi_ac;
587 break;
588 case CXD2880_TNRDMD_CLOCKMODE_B:
589 data = bw5_nomi_b;
590 break;
591 default:
592 return -EINVAL;
593 }
594
595 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
596 CXD2880_IO_TGT_DMD,
597 0x10, data, 6);
598 if (ret)
599 return ret;
600
601 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
602 CXD2880_IO_TGT_DMD,
603 0x4a, 0x06);
604 if (ret)
605 return ret;
606
607 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
608 CXD2880_IO_TGT_DMD,
609 0x19, gtdofst, 2);
610 if (ret)
611 return ret;
612
613 switch (clk_mode) {
614 case CXD2880_TNRDMD_CLOCKMODE_A:
615 data = bw5_sst_a;
616 break;
617 case CXD2880_TNRDMD_CLOCKMODE_B:
618 data = bw5_sst_b;
619 break;
620 case CXD2880_TNRDMD_CLOCKMODE_C:
621 data = bw5_sst_c;
622 break;
623 default:
624 return -EINVAL;
625 }
626
627 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
628 CXD2880_IO_TGT_DMD,
629 0x1b, data, 2);
630 if (ret)
631 return ret;
632
633 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
634 switch (clk_mode) {
635 case CXD2880_TNRDMD_CLOCKMODE_A:
636 data = bw5_mrc_a;
637 break;
638 case CXD2880_TNRDMD_CLOCKMODE_B:
639 data = bw5_mrc_b;
640 break;
641 case CXD2880_TNRDMD_CLOCKMODE_C:
642 data = bw5_mrc_c;
643 break;
644 default:
645 return -EINVAL;
646 }
647
648 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
649 CXD2880_IO_TGT_DMD,
650 0x4b, data, 9);
651 if (ret)
652 return ret;
653 }
654 break;
655
656 case CXD2880_DTV_BW_1_7_MHZ:
657
658 switch (clk_mode) {
659 case CXD2880_TNRDMD_CLOCKMODE_A:
660 data = bw1_7_nomi_a;
661 break;
662 case CXD2880_TNRDMD_CLOCKMODE_C:
663 data = bw1_7_nomi_c;
664 break;
665 case CXD2880_TNRDMD_CLOCKMODE_B:
666 data = bw1_7_nomi_b;
667 break;
668 default:
669 return -EINVAL;
670 }
671
672 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
673 CXD2880_IO_TGT_DMD,
674 0x10, data, 6);
675 if (ret)
676 return ret;
677
678 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
679 CXD2880_IO_TGT_DMD,
680 0x4a, 0x03);
681 if (ret)
682 return ret;
683
684 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
685 CXD2880_IO_TGT_DMD,
686 0x19, gtdofst, 2);
687 if (ret)
688 return ret;
689
690 switch (clk_mode) {
691 case CXD2880_TNRDMD_CLOCKMODE_A:
692 data = bw1_7_sst_a;
693 break;
694 case CXD2880_TNRDMD_CLOCKMODE_B:
695 data = bw1_7_sst_b;
696 break;
697 case CXD2880_TNRDMD_CLOCKMODE_C:
698 data = bw1_7_sst_c;
699 break;
700 default:
701 return -EINVAL;
702 }
703
704 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
705 CXD2880_IO_TGT_DMD,
706 0x1b, data, 2);
707 if (ret)
708 return ret;
709
710 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
711 switch (clk_mode) {
712 case CXD2880_TNRDMD_CLOCKMODE_A:
713 data = bw1_7_mrc_a;
714 break;
715 case CXD2880_TNRDMD_CLOCKMODE_B:
716 data = bw1_7_mrc_b;
717 break;
718 case CXD2880_TNRDMD_CLOCKMODE_C:
719 data = bw1_7_mrc_c;
720 break;
721 default:
722 return -EINVAL;
723 }
724
725 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
726 CXD2880_IO_TGT_DMD,
727 0x4b, data, 9);
728 if (ret)
729 return ret;
730 }
731 break;
732
733 default:
734 return -EINVAL;
735 }
736
737 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
738 CXD2880_IO_TGT_DMD,
739 0x00, 0x00);
740 if (ret)
741 return ret;
742
743 return tnr_dmd->io->write_reg(tnr_dmd->io,
744 CXD2880_IO_TGT_DMD,
745 0xfd, 0x01);
746 }
747
x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd * tnr_dmd)748 static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd
749 *tnr_dmd)
750 {
751 static const u8 difint_clip[] = {
752 0, 1, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32
753 };
754 int ret = 0;
755
756 if (!tnr_dmd)
757 return -EINVAL;
758
759 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
760 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
761 CXD2880_IO_TGT_DMD,
762 0x00, 0x1d);
763 if (ret)
764 return ret;
765
766 ret = tnr_dmd->io->write_regs(tnr_dmd->io,
767 CXD2880_IO_TGT_DMD,
768 0x47, difint_clip, 12);
769 }
770
771 return ret;
772 }
773
dvbt2_set_profile(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_dvbt2_profile profile)774 static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
775 enum cxd2880_dvbt2_profile profile)
776 {
777 u8 t2_mode_tune_mode = 0;
778 u8 seq_not2_dtime = 0;
779 u8 dtime1 = 0;
780 u8 dtime2 = 0;
781 int ret;
782
783 if (!tnr_dmd)
784 return -EINVAL;
785
786 switch (tnr_dmd->clk_mode) {
787 case CXD2880_TNRDMD_CLOCKMODE_A:
788 dtime1 = 0x27;
789 dtime2 = 0x0c;
790 break;
791 case CXD2880_TNRDMD_CLOCKMODE_B:
792 dtime1 = 0x2c;
793 dtime2 = 0x0d;
794 break;
795 case CXD2880_TNRDMD_CLOCKMODE_C:
796 dtime1 = 0x2e;
797 dtime2 = 0x0e;
798 break;
799 default:
800 return -EINVAL;
801 }
802
803 switch (profile) {
804 case CXD2880_DVBT2_PROFILE_BASE:
805 t2_mode_tune_mode = 0x01;
806 seq_not2_dtime = dtime2;
807 break;
808
809 case CXD2880_DVBT2_PROFILE_LITE:
810 t2_mode_tune_mode = 0x05;
811 seq_not2_dtime = dtime1;
812 break;
813
814 case CXD2880_DVBT2_PROFILE_ANY:
815 t2_mode_tune_mode = 0x00;
816 seq_not2_dtime = dtime1;
817 break;
818
819 default:
820 return -EINVAL;
821 }
822
823 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
824 CXD2880_IO_TGT_DMD,
825 0x00, 0x2e);
826 if (ret)
827 return ret;
828
829 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
830 CXD2880_IO_TGT_DMD,
831 0x10, t2_mode_tune_mode);
832 if (ret)
833 return ret;
834
835 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
836 CXD2880_IO_TGT_DMD,
837 0x00, 0x04);
838 if (ret)
839 return ret;
840
841 return tnr_dmd->io->write_reg(tnr_dmd->io,
842 CXD2880_IO_TGT_DMD,
843 0x2c, seq_not2_dtime);
844 }
845
cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd * tnr_dmd,struct cxd2880_dvbt2_tune_param * tune_param)846 int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,
847 struct cxd2880_dvbt2_tune_param
848 *tune_param)
849 {
850 int ret;
851
852 if (!tnr_dmd || !tune_param)
853 return -EINVAL;
854
855 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
856 return -EINVAL;
857
858 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
859 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
860 return -EINVAL;
861
862 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN &&
863 tune_param->profile == CXD2880_DVBT2_PROFILE_ANY)
864 return -ENOTTY;
865
866 ret =
867 cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,
868 tune_param->center_freq_khz,
869 tune_param->bandwidth, 0, 0);
870 if (ret)
871 return ret;
872
873 ret =
874 x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,
875 tnr_dmd->clk_mode);
876 if (ret)
877 return ret;
878
879 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
880 ret =
881 x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,
882 tune_param->bandwidth,
883 tnr_dmd->diver_sub->clk_mode);
884 if (ret)
885 return ret;
886 }
887
888 ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);
889 if (ret)
890 return ret;
891
892 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
893 ret =
894 dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);
895 if (ret)
896 return ret;
897 }
898
899 if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO)
900 ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);
901 else
902 ret =
903 cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,
904 (u8)(tune_param->data_plp_id));
905
906 return ret;
907 }
908
cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd * tnr_dmd,struct cxd2880_dvbt2_tune_param * tune_param)909 int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,
910 struct cxd2880_dvbt2_tune_param
911 *tune_param)
912 {
913 u8 en_fef_intmtnt_ctrl = 1;
914 int ret;
915
916 if (!tnr_dmd || !tune_param)
917 return -EINVAL;
918
919 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
920 return -EINVAL;
921
922 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
923 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
924 return -EINVAL;
925
926 switch (tune_param->profile) {
927 case CXD2880_DVBT2_PROFILE_BASE:
928 en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;
929 break;
930 case CXD2880_DVBT2_PROFILE_LITE:
931 en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;
932 break;
933 case CXD2880_DVBT2_PROFILE_ANY:
934 if (tnr_dmd->en_fef_intmtnt_base &&
935 tnr_dmd->en_fef_intmtnt_lite)
936 en_fef_intmtnt_ctrl = 1;
937 else
938 en_fef_intmtnt_ctrl = 0;
939 break;
940 default:
941 return -EINVAL;
942 }
943
944 ret =
945 cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,
946 CXD2880_DTV_SYS_DVBT2,
947 en_fef_intmtnt_ctrl);
948 if (ret)
949 return ret;
950
951 tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
952 tnr_dmd->frequency_khz = tune_param->center_freq_khz;
953 tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;
954 tnr_dmd->bandwidth = tune_param->bandwidth;
955
956 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
957 tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
958 tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
959 tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;
960 tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
961 }
962
963 return 0;
964 }
965
cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd * tnr_dmd)966 int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd
967 *tnr_dmd)
968 {
969 int ret;
970
971 if (!tnr_dmd)
972 return -EINVAL;
973
974 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
975 return -EINVAL;
976
977 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
978 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
979 return -EINVAL;
980
981 ret = x_sleep_dvbt2_demod_setting(tnr_dmd);
982 if (ret)
983 return ret;
984
985 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
986 ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);
987
988 return ret;
989 }
990
cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_tnrdmd_lock_result * lock)991 int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd
992 *tnr_dmd,
993 enum
994 cxd2880_tnrdmd_lock_result
995 *lock)
996 {
997 int ret;
998
999 u8 sync_stat = 0;
1000 u8 ts_lock = 0;
1001 u8 unlock_detected = 0;
1002 u8 unlock_detected_sub = 0;
1003
1004 if (!tnr_dmd || !lock)
1005 return -EINVAL;
1006
1007 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1008 return -EINVAL;
1009
1010 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1011 return -EINVAL;
1012
1013 ret =
1014 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
1015 &unlock_detected);
1016 if (ret)
1017 return ret;
1018
1019 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
1020 if (sync_stat == 6)
1021 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
1022 else if (unlock_detected)
1023 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
1024 else
1025 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
1026
1027 return 0;
1028 }
1029
1030 if (sync_stat == 6) {
1031 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
1032 return 0;
1033 }
1034
1035 ret =
1036 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
1037 &unlock_detected_sub);
1038 if (ret)
1039 return ret;
1040
1041 if (sync_stat == 6)
1042 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
1043 else if (unlock_detected && unlock_detected_sub)
1044 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
1045 else
1046 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
1047
1048 return 0;
1049 }
1050
cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd * tnr_dmd,enum cxd2880_tnrdmd_lock_result * lock)1051 int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd
1052 *tnr_dmd,
1053 enum
1054 cxd2880_tnrdmd_lock_result
1055 *lock)
1056 {
1057 int ret;
1058
1059 u8 sync_stat = 0;
1060 u8 ts_lock = 0;
1061 u8 unlock_detected = 0;
1062 u8 unlock_detected_sub = 0;
1063
1064 if (!tnr_dmd || !lock)
1065 return -EINVAL;
1066
1067 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1068 return -EINVAL;
1069
1070 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1071 return -EINVAL;
1072
1073 ret =
1074 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
1075 &unlock_detected);
1076 if (ret)
1077 return ret;
1078
1079 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
1080 if (ts_lock)
1081 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
1082 else if (unlock_detected)
1083 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
1084 else
1085 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
1086
1087 return 0;
1088 }
1089
1090 if (ts_lock) {
1091 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
1092 return 0;
1093 } else if (!unlock_detected) {
1094 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
1095 return 0;
1096 }
1097
1098 ret =
1099 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,
1100 &unlock_detected_sub);
1101 if (ret)
1102 return ret;
1103
1104 if (unlock_detected && unlock_detected_sub)
1105 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
1106 else
1107 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
1108
1109 return 0;
1110 }
1111
cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd * tnr_dmd,u8 auto_plp,u8 plp_id)1112 int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd
1113 *tnr_dmd, u8 auto_plp,
1114 u8 plp_id)
1115 {
1116 int ret;
1117
1118 if (!tnr_dmd)
1119 return -EINVAL;
1120
1121 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1122 return -EINVAL;
1123
1124 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
1125 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1126 return -EINVAL;
1127
1128 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1129 CXD2880_IO_TGT_DMD,
1130 0x00, 0x23);
1131 if (ret)
1132 return ret;
1133
1134 if (!auto_plp) {
1135 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1136 CXD2880_IO_TGT_DMD,
1137 0xaf, plp_id);
1138 if (ret)
1139 return ret;
1140 }
1141
1142 return tnr_dmd->io->write_reg(tnr_dmd->io,
1143 CXD2880_IO_TGT_DMD,
1144 0xad, auto_plp ? 0x00 : 0x01);
1145 }
1146
cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd * tnr_dmd)1147 int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd
1148 *tnr_dmd)
1149 {
1150 struct cxd2880_dvbt2_ofdm ofdm;
1151 static const u8 data[] = { 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 1, 0};
1152 int ret;
1153
1154 if (!tnr_dmd)
1155 return -EINVAL;
1156
1157 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1158 return -EINVAL;
1159
1160 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1161 return -EINVAL;
1162
1163 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)
1164 return 0;
1165
1166 ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);
1167 if (ret)
1168 return ret;
1169
1170 if (!ofdm.mixed)
1171 return 0;
1172
1173 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1174 CXD2880_IO_TGT_DMD,
1175 0x00, 0x1d);
1176 if (ret)
1177 return ret;
1178
1179 return tnr_dmd->io->write_regs(tnr_dmd->io,
1180 CXD2880_IO_TGT_DMD,
1181 0x47, data, 12);
1182 }
1183
cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd * tnr_dmd,u8 * l1_post_valid)1184 int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd
1185 *tnr_dmd,
1186 u8 *l1_post_valid)
1187 {
1188 int ret;
1189
1190 u8 data;
1191
1192 if (!tnr_dmd || !l1_post_valid)
1193 return -EINVAL;
1194
1195 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
1196 return -EINVAL;
1197
1198 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
1199 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
1200 return -EINVAL;
1201
1202 ret = tnr_dmd->io->write_reg(tnr_dmd->io,
1203 CXD2880_IO_TGT_DMD,
1204 0x00, 0x0b);
1205 if (ret)
1206 return ret;
1207
1208 ret = tnr_dmd->io->read_regs(tnr_dmd->io,
1209 CXD2880_IO_TGT_DMD,
1210 0x86, &data, 1);
1211 if (ret)
1212 return ret;
1213
1214 *l1_post_valid = data & 0x01;
1215
1216 return ret;
1217 }
1218