Linux-libre 5.3.12-gnu
[librecmc/linux-libre.git] / drivers / media / dvb-frontends / cxd2880 / cxd2880_tnrdmd_dvbt.c
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
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
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
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
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
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
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
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 ret;
837         }
838
839         if (sync_stat == 6) {
840                 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
841                 return ret;
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 ret;
858 }
859
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 ret;
897         }
898
899         if (ts_lock) {
900                 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
901                 return ret;
902         } else if (!unlock_detected) {
903                 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
904                 return ret;
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 ret;
919 }