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 | |
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(io: tnr_dmd->io, |
166 | tgt: CXD2880_IO_TGT_SYS, |
167 | reg_value: 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(io: tnr_dmd->io, |
173 | tgt: CXD2880_IO_TGT_DMD, |
174 | reg_value: 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 | |
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 | |
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 | |
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, sys: CXD2880_DTV_SYS_DVBT2, |
868 | frequency_khz: tune_param->center_freq_khz, |
869 | bandwidth: tune_param->bandwidth, one_seg_opt: 0, one_seg_opt_shft_dir: 0); |
870 | if (ret) |
871 | return ret; |
872 | |
873 | ret = |
874 | x_tune_dvbt2_demod_setting(tnr_dmd, bandwidth: tune_param->bandwidth, |
875 | clk_mode: 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: tnr_dmd->diver_sub, |
882 | bandwidth: tune_param->bandwidth, |
883 | clk_mode: tnr_dmd->diver_sub->clk_mode); |
884 | if (ret) |
885 | return ret; |
886 | } |
887 | |
888 | ret = dvbt2_set_profile(tnr_dmd, profile: 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: tnr_dmd->diver_sub, profile: 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, auto_plp: 1, plp_id: 0); |
901 | else |
902 | ret = |
903 | cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, auto_plp: 0, |
904 | plp_id: (u8)(tune_param->data_plp_id)); |
905 | |
906 | return ret; |
907 | } |
908 | |
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 | sys: 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 | |
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: tnr_dmd->diver_sub); |
987 | |
988 | return ret; |
989 | } |
990 | |
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: &sync_stat, ts_lock_stat: &ts_lock, |
1015 | unlock_detected: &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: &sync_stat, |
1037 | unlock_detected: &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 | |
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: &sync_stat, ts_lock_stat: &ts_lock, |
1075 | unlock_detected: &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: &sync_stat, |
1100 | unlock_detected: &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 | |
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 | |
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: &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 | |
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 | |