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
15static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
16 {0x00, 0x00}, {0x31, 0x01},
17};
18
19static 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
24static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
25 {0x00, 0x12}, {0x44, 0x00},
26};
27
28static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
29 {0x00, 0x11}, {0x87, 0xd2},
30};
31
32static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
33 {0x00, 0x00}, {0xfd, 0x01},
34};
35
36static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
37 {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
38};
39
40static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
41 {0x00, 0x11}, {0x87, 0x04},
42};
43
44static 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(io: tnr_dmd->io,
106 tgt: CXD2880_IO_TGT_SYS,
107 reg_value: 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(io: tnr_dmd->io,
161 tgt: CXD2880_IO_TGT_DMD,
162 reg_value: 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(io: tnr_dmd->io,
176 tgt: CXD2880_IO_TGT_DMD,
177 reg_value: 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(io: tnr_dmd->io,
185 tgt: CXD2880_IO_TGT_DMD,
186 reg_value: 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(io: tnr_dmd->io,
648 tgt: CXD2880_IO_TGT_DMD,
649 reg_value: tune_dmd_setting_seq5,
650 ARRAY_SIZE(tune_dmd_setting_seq5));
651}
652
653static 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(io: tnr_dmd->io,
662 tgt: CXD2880_IO_TGT_DMD,
663 reg_value: 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(io: tnr_dmd->io,
670 tgt: CXD2880_IO_TGT_DMD,
671 reg_value: sleep_dmd_setting_seq2,
672 ARRAY_SIZE(sleep_dmd_setting_seq2));
673
674 return ret;
675}
676
677static 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
698int 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, sys: CXD2880_DTV_SYS_DVBT,
716 frequency_khz: tune_param->center_freq_khz,
717 bandwidth: tune_param->bandwidth, one_seg_opt: 0, one_seg_opt_shft_dir: 0);
718 if (ret)
719 return ret;
720
721 ret =
722 x_tune_dvbt_demod_setting(tnr_dmd, bandwidth: tune_param->bandwidth,
723 clk_mode: 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: tnr_dmd->diver_sub,
730 bandwidth: tune_param->bandwidth,
731 clk_mode: tnr_dmd->diver_sub->clk_mode);
732 if (ret)
733 return ret;
734 }
735
736 return dvbt_set_profile(tnr_dmd, profile: tune_param->profile);
737}
738
739int 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, sys: CXD2880_DTV_SYS_DVBT,
757 en_fef_intmtnt_ctrl: 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
776int 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: tnr_dmd->diver_sub);
796
797 return ret;
798}
799
800int 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: &sync_stat, ts_lock_stat: &ts_lock,
824 unlock_detected: &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: &sync_stat,
846 unlock_detected: &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
860int 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: &sync_stat, ts_lock_stat: &ts_lock,
884 unlock_detected: &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: &sync_stat,
909 unlock_detected: &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

source code of linux/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c