Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * cxd2880_tnrdmd_dvbt.c
0004  * Sony CXD2880 DVB-T2/T tuner + demodulator driver
0005  * control functions for DVB-T
0006  *
0007  * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
0008  */
0009 
0010 #include <media/dvb_frontend.h>
0011 
0012 #include "cxd2880_tnrdmd_dvbt.h"
0013 #include "cxd2880_tnrdmd_dvbt_mon.h"
0014 
0015 static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
0016     {0x00, 0x00}, {0x31, 0x01},
0017 };
0018 
0019 static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
0020     {0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03},
0021     {0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25},
0022 };
0023 
0024 static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
0025     {0x00, 0x12}, {0x44, 0x00},
0026 };
0027 
0028 static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
0029     {0x00, 0x11}, {0x87, 0xd2},
0030 };
0031 
0032 static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
0033     {0x00, 0x00}, {0xfd, 0x01},
0034 };
0035 
0036 static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
0037     {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
0038 };
0039 
0040 static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
0041     {0x00, 0x11}, {0x87, 0x04},
0042 };
0043 
0044 static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
0045                      *tnr_dmd,
0046                      enum cxd2880_dtv_bandwidth
0047                      bandwidth,
0048                      enum cxd2880_tnrdmd_clockmode
0049                      clk_mode)
0050 {
0051     static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 };
0052     static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 };
0053     static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 };
0054     static const u8 ratectl_margin[2] = { 0x01, 0xf0 };
0055     static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 };
0056     static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa };
0057     static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 };
0058 
0059     static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00};
0060     static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa};
0061     static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 };
0062     static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 };
0063     static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 };
0064     static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 };
0065     static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 };
0066     static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 };
0067     static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 };
0068 
0069     static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00};
0070     static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55};
0071     static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c };
0072     static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 };
0073     static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 };
0074     static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 };
0075     static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa };
0076     static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
0077     static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 };
0078 
0079     static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00};
0080     static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38};
0081     static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 };
0082     static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 };
0083     static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c };
0084     static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
0085     static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 };
0086     static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff };
0087     static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 };
0088 
0089     static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99};
0090     static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa};
0091     static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d };
0092     static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 };
0093     static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 };
0094     static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 };
0095     static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 };
0096     static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc };
0097     static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 };
0098     const u8 *data = NULL;
0099     u8 sst_data;
0100     int ret;
0101 
0102     if (!tnr_dmd)
0103         return -EINVAL;
0104 
0105     ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
0106                       CXD2880_IO_TGT_SYS,
0107                       tune_dmd_setting_seq1,
0108                       ARRAY_SIZE(tune_dmd_setting_seq1));
0109     if (ret)
0110         return ret;
0111 
0112     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0113                      CXD2880_IO_TGT_DMD,
0114                      0x00, 0x04);
0115     if (ret)
0116         return ret;
0117 
0118     switch (clk_mode) {
0119     case CXD2880_TNRDMD_CLOCKMODE_A:
0120         data = clk_mode_ckffrq_a;
0121         break;
0122     case CXD2880_TNRDMD_CLOCKMODE_B:
0123         data = clk_mode_ckffrq_b;
0124         break;
0125     case CXD2880_TNRDMD_CLOCKMODE_C:
0126         data = clk_mode_ckffrq_c;
0127         break;
0128     default:
0129         return -EINVAL;
0130     }
0131 
0132     ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0133                       CXD2880_IO_TGT_DMD,
0134                       0x65, data, 2);
0135     if (ret)
0136         return ret;
0137 
0138     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0139                      CXD2880_IO_TGT_DMD,
0140                      0x5d, 0x07);
0141     if (ret)
0142         return ret;
0143 
0144     if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
0145         u8 data[2] = { 0x01, 0x01 };
0146 
0147         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0148                          CXD2880_IO_TGT_DMD,
0149                          0x00, 0x00);
0150         if (ret)
0151             return ret;
0152 
0153         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0154                           CXD2880_IO_TGT_DMD,
0155                           0xce, data, 2);
0156         if (ret)
0157             return ret;
0158     }
0159 
0160     ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
0161                       CXD2880_IO_TGT_DMD,
0162                       tune_dmd_setting_seq2,
0163                       ARRAY_SIZE(tune_dmd_setting_seq2));
0164     if (ret)
0165         return ret;
0166 
0167     ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0168                       CXD2880_IO_TGT_DMD,
0169                       0xf0, ratectl_margin, 2);
0170     if (ret)
0171         return ret;
0172 
0173     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN ||
0174         tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
0175         ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
0176                           CXD2880_IO_TGT_DMD,
0177                           tune_dmd_setting_seq3,
0178                           ARRAY_SIZE(tune_dmd_setting_seq3));
0179         if (ret)
0180             return ret;
0181     }
0182 
0183     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) {
0184         ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
0185                           CXD2880_IO_TGT_DMD,
0186                           tune_dmd_setting_seq4,
0187                           ARRAY_SIZE(tune_dmd_setting_seq4));
0188         if (ret)
0189             return ret;
0190     }
0191 
0192     if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {
0193         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0194                          CXD2880_IO_TGT_DMD,
0195                          0x00, 0x04);
0196         if (ret)
0197             return ret;
0198 
0199         switch (clk_mode) {
0200         case CXD2880_TNRDMD_CLOCKMODE_A:
0201             data = maxclkcnt_a;
0202             break;
0203         case CXD2880_TNRDMD_CLOCKMODE_B:
0204             data = maxclkcnt_b;
0205             break;
0206         case CXD2880_TNRDMD_CLOCKMODE_C:
0207             data = maxclkcnt_c;
0208             break;
0209         default:
0210             return -EINVAL;
0211         }
0212 
0213         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0214                           CXD2880_IO_TGT_DMD,
0215                           0x68, data, 3);
0216         if (ret)
0217             return ret;
0218     }
0219 
0220     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0221                      CXD2880_IO_TGT_DMD,
0222                      0x00, 0x04);
0223     if (ret)
0224         return ret;
0225 
0226     switch (bandwidth) {
0227     case CXD2880_DTV_BW_8_MHZ:
0228         switch (clk_mode) {
0229         case CXD2880_TNRDMD_CLOCKMODE_A:
0230         case CXD2880_TNRDMD_CLOCKMODE_C:
0231             data = bw8_nomi_ac;
0232             break;
0233         case CXD2880_TNRDMD_CLOCKMODE_B:
0234             data = bw8_nomi_b;
0235             break;
0236         default:
0237             return -EINVAL;
0238         }
0239 
0240         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0241                           CXD2880_IO_TGT_DMD,
0242                           0x60, data, 5);
0243         if (ret)
0244             return ret;
0245 
0246         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0247                          CXD2880_IO_TGT_DMD,
0248                          0x4a, 0x00);
0249         if (ret)
0250             return ret;
0251 
0252         switch (clk_mode) {
0253         case CXD2880_TNRDMD_CLOCKMODE_A:
0254             data = bw8_gtdofst_a;
0255             break;
0256         case CXD2880_TNRDMD_CLOCKMODE_B:
0257             data = bw8_gtdofst_b;
0258             break;
0259         case CXD2880_TNRDMD_CLOCKMODE_C:
0260             data = bw8_gtdofst_c;
0261             break;
0262         default:
0263             return -EINVAL;
0264         }
0265 
0266         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0267                           CXD2880_IO_TGT_DMD,
0268                           0x7d, data, 2);
0269         if (ret)
0270             return ret;
0271 
0272         switch (clk_mode) {
0273         case CXD2880_TNRDMD_CLOCKMODE_A:
0274         case CXD2880_TNRDMD_CLOCKMODE_B:
0275             sst_data = 0x35;
0276             break;
0277         case CXD2880_TNRDMD_CLOCKMODE_C:
0278             sst_data = 0x34;
0279             break;
0280         default:
0281             return -EINVAL;
0282         }
0283 
0284         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0285                          CXD2880_IO_TGT_DMD,
0286                          0x71, sst_data);
0287         if (ret)
0288             return ret;
0289 
0290         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
0291             switch (clk_mode) {
0292             case CXD2880_TNRDMD_CLOCKMODE_A:
0293                 data = bw8_mrc_a;
0294                 break;
0295             case CXD2880_TNRDMD_CLOCKMODE_B:
0296                 data = bw8_mrc_b;
0297                 break;
0298             case CXD2880_TNRDMD_CLOCKMODE_C:
0299                 data = bw8_mrc_c;
0300                 break;
0301             default:
0302                 return -EINVAL;
0303             }
0304 
0305             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0306                               CXD2880_IO_TGT_DMD,
0307                               0x4b, &data[0], 2);
0308             if (ret)
0309                 return ret;
0310 
0311             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0312                               CXD2880_IO_TGT_DMD,
0313                               0x51, &data[2], 3);
0314             if (ret)
0315                 return ret;
0316         }
0317 
0318         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0319                           CXD2880_IO_TGT_DMD,
0320                           0x72, &bw8_notch[0], 2);
0321         if (ret)
0322             return ret;
0323 
0324         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0325                           CXD2880_IO_TGT_DMD,
0326                           0x6b, &bw8_notch[2], 2);
0327         if (ret)
0328             return ret;
0329         break;
0330 
0331     case CXD2880_DTV_BW_7_MHZ:
0332         switch (clk_mode) {
0333         case CXD2880_TNRDMD_CLOCKMODE_A:
0334         case CXD2880_TNRDMD_CLOCKMODE_C:
0335             data = bw7_nomi_ac;
0336             break;
0337         case CXD2880_TNRDMD_CLOCKMODE_B:
0338             data = bw7_nomi_b;
0339             break;
0340         default:
0341             return -EINVAL;
0342         }
0343 
0344         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0345                           CXD2880_IO_TGT_DMD,
0346                           0x60, data, 5);
0347         if (ret)
0348             return ret;
0349 
0350         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0351                          CXD2880_IO_TGT_DMD,
0352                          0x4a, 0x02);
0353         if (ret)
0354             return ret;
0355 
0356         switch (clk_mode) {
0357         case CXD2880_TNRDMD_CLOCKMODE_A:
0358             data = bw7_gtdofst_a;
0359             break;
0360         case CXD2880_TNRDMD_CLOCKMODE_B:
0361             data = bw7_gtdofst_b;
0362             break;
0363         case CXD2880_TNRDMD_CLOCKMODE_C:
0364             data = bw7_gtdofst_c;
0365             break;
0366         default:
0367             return -EINVAL;
0368         }
0369 
0370         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0371                           CXD2880_IO_TGT_DMD,
0372                           0x7d, data, 2);
0373         if (ret)
0374             return ret;
0375 
0376         switch (clk_mode) {
0377         case CXD2880_TNRDMD_CLOCKMODE_A:
0378         case CXD2880_TNRDMD_CLOCKMODE_B:
0379             sst_data = 0x2f;
0380             break;
0381         case CXD2880_TNRDMD_CLOCKMODE_C:
0382             sst_data = 0x2e;
0383             break;
0384         default:
0385             return -EINVAL;
0386         }
0387 
0388         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0389                          CXD2880_IO_TGT_DMD,
0390                          0x71, sst_data);
0391         if (ret)
0392             return ret;
0393 
0394         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
0395             switch (clk_mode) {
0396             case CXD2880_TNRDMD_CLOCKMODE_A:
0397                 data = bw7_mrc_a;
0398                 break;
0399             case CXD2880_TNRDMD_CLOCKMODE_B:
0400                 data = bw7_mrc_b;
0401                 break;
0402             case CXD2880_TNRDMD_CLOCKMODE_C:
0403                 data = bw7_mrc_c;
0404                 break;
0405             default:
0406                 return -EINVAL;
0407             }
0408 
0409             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0410                               CXD2880_IO_TGT_DMD,
0411                               0x4b, &data[0], 2);
0412             if (ret)
0413                 return ret;
0414 
0415             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0416                               CXD2880_IO_TGT_DMD,
0417                               0x51, &data[2], 3);
0418             if (ret)
0419                 return ret;
0420         }
0421 
0422         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0423                           CXD2880_IO_TGT_DMD,
0424                           0x72, &bw7_notch[0], 2);
0425         if (ret)
0426             return ret;
0427 
0428         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0429                           CXD2880_IO_TGT_DMD,
0430                           0x6b, &bw7_notch[2], 2);
0431         if (ret)
0432             return ret;
0433         break;
0434 
0435     case CXD2880_DTV_BW_6_MHZ:
0436         switch (clk_mode) {
0437         case CXD2880_TNRDMD_CLOCKMODE_A:
0438         case CXD2880_TNRDMD_CLOCKMODE_C:
0439             data = bw6_nomi_ac;
0440             break;
0441         case CXD2880_TNRDMD_CLOCKMODE_B:
0442             data = bw6_nomi_b;
0443             break;
0444         default:
0445             return -EINVAL;
0446         }
0447 
0448         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0449                           CXD2880_IO_TGT_DMD,
0450                           0x60, data, 5);
0451         if (ret)
0452             return ret;
0453 
0454         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0455                          CXD2880_IO_TGT_DMD,
0456                          0x4a, 0x04);
0457         if (ret)
0458             return ret;
0459 
0460         switch (clk_mode) {
0461         case CXD2880_TNRDMD_CLOCKMODE_A:
0462             data = bw6_gtdofst_a;
0463             break;
0464         case CXD2880_TNRDMD_CLOCKMODE_B:
0465             data = bw6_gtdofst_b;
0466             break;
0467         case CXD2880_TNRDMD_CLOCKMODE_C:
0468             data = bw6_gtdofst_c;
0469             break;
0470         default:
0471             return -EINVAL;
0472         }
0473 
0474         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0475                           CXD2880_IO_TGT_DMD,
0476                           0x7d, data, 2);
0477         if (ret)
0478             return ret;
0479 
0480         switch (clk_mode) {
0481         case CXD2880_TNRDMD_CLOCKMODE_A:
0482         case CXD2880_TNRDMD_CLOCKMODE_C:
0483             sst_data = 0x29;
0484             break;
0485         case CXD2880_TNRDMD_CLOCKMODE_B:
0486             sst_data = 0x2a;
0487             break;
0488         default:
0489             return -EINVAL;
0490         }
0491 
0492         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0493                          CXD2880_IO_TGT_DMD,
0494                          0x71, sst_data);
0495         if (ret)
0496             return ret;
0497 
0498         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
0499             switch (clk_mode) {
0500             case CXD2880_TNRDMD_CLOCKMODE_A:
0501                 data = bw6_mrc_a;
0502                 break;
0503             case CXD2880_TNRDMD_CLOCKMODE_B:
0504                 data = bw6_mrc_b;
0505                 break;
0506             case CXD2880_TNRDMD_CLOCKMODE_C:
0507                 data = bw6_mrc_c;
0508                 break;
0509             default:
0510                 return -EINVAL;
0511             }
0512 
0513             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0514                               CXD2880_IO_TGT_DMD,
0515                               0x4b, &data[0], 2);
0516             if (ret)
0517                 return ret;
0518 
0519             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0520                               CXD2880_IO_TGT_DMD,
0521                               0x51, &data[2], 3);
0522             if (ret)
0523                 return ret;
0524         }
0525 
0526         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0527                           CXD2880_IO_TGT_DMD,
0528                           0x72, &bw6_notch[0], 2);
0529         if (ret)
0530             return ret;
0531 
0532         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0533                           CXD2880_IO_TGT_DMD,
0534                           0x6b, &bw6_notch[2], 2);
0535         if (ret)
0536             return ret;
0537         break;
0538 
0539     case CXD2880_DTV_BW_5_MHZ:
0540         switch (clk_mode) {
0541         case CXD2880_TNRDMD_CLOCKMODE_A:
0542         case CXD2880_TNRDMD_CLOCKMODE_C:
0543             data = bw5_nomi_ac;
0544             break;
0545         case CXD2880_TNRDMD_CLOCKMODE_B:
0546             data = bw5_nomi_b;
0547             break;
0548         default:
0549             return -EINVAL;
0550         }
0551 
0552         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0553                           CXD2880_IO_TGT_DMD,
0554                           0x60, data, 5);
0555         if (ret)
0556             return ret;
0557 
0558         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0559                          CXD2880_IO_TGT_DMD,
0560                          0x4a, 0x06);
0561         if (ret)
0562             return ret;
0563 
0564         switch (clk_mode) {
0565         case CXD2880_TNRDMD_CLOCKMODE_A:
0566             data = bw5_gtdofst_a;
0567             break;
0568         case CXD2880_TNRDMD_CLOCKMODE_B:
0569             data = bw5_gtdofst_b;
0570             break;
0571         case CXD2880_TNRDMD_CLOCKMODE_C:
0572             data = bw5_gtdofst_c;
0573             break;
0574         default:
0575             return -EINVAL;
0576         }
0577 
0578         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0579                           CXD2880_IO_TGT_DMD,
0580                           0x7d, data, 2);
0581         if (ret)
0582             return ret;
0583 
0584         switch (clk_mode) {
0585         case CXD2880_TNRDMD_CLOCKMODE_A:
0586         case CXD2880_TNRDMD_CLOCKMODE_B:
0587             sst_data = 0x24;
0588             break;
0589         case CXD2880_TNRDMD_CLOCKMODE_C:
0590             sst_data = 0x23;
0591             break;
0592         default:
0593             return -EINVAL;
0594         }
0595 
0596         ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0597                          CXD2880_IO_TGT_DMD,
0598                          0x71, sst_data);
0599         if (ret)
0600             return ret;
0601 
0602         if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
0603             switch (clk_mode) {
0604             case CXD2880_TNRDMD_CLOCKMODE_A:
0605                 data = bw5_mrc_a;
0606                 break;
0607             case CXD2880_TNRDMD_CLOCKMODE_B:
0608                 data = bw5_mrc_b;
0609                 break;
0610             case CXD2880_TNRDMD_CLOCKMODE_C:
0611                 data = bw5_mrc_c;
0612                 break;
0613             default:
0614                 return -EINVAL;
0615             }
0616 
0617             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0618                               CXD2880_IO_TGT_DMD,
0619                               0x4b, &data[0], 2);
0620             if (ret)
0621                 return ret;
0622 
0623             ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0624                               CXD2880_IO_TGT_DMD,
0625                               0x51, &data[2], 3);
0626             if (ret)
0627                 return ret;
0628         }
0629 
0630         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0631                           CXD2880_IO_TGT_DMD,
0632                           0x72, &bw5_notch[0], 2);
0633         if (ret)
0634             return ret;
0635 
0636         ret = tnr_dmd->io->write_regs(tnr_dmd->io,
0637                           CXD2880_IO_TGT_DMD,
0638                           0x6b, &bw5_notch[2], 2);
0639         if (ret)
0640             return ret;
0641         break;
0642 
0643     default:
0644         return -EINVAL;
0645     }
0646 
0647     return cxd2880_io_write_multi_regs(tnr_dmd->io,
0648                        CXD2880_IO_TGT_DMD,
0649                        tune_dmd_setting_seq5,
0650                        ARRAY_SIZE(tune_dmd_setting_seq5));
0651 }
0652 
0653 static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
0654                            *tnr_dmd)
0655 {
0656     int ret;
0657 
0658     if (!tnr_dmd)
0659         return -EINVAL;
0660 
0661     ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
0662                       CXD2880_IO_TGT_DMD,
0663                       sleep_dmd_setting_seq1,
0664                       ARRAY_SIZE(sleep_dmd_setting_seq1));
0665     if (ret)
0666         return ret;
0667 
0668     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0669         ret = cxd2880_io_write_multi_regs(tnr_dmd->io,
0670                           CXD2880_IO_TGT_DMD,
0671                           sleep_dmd_setting_seq2,
0672                           ARRAY_SIZE(sleep_dmd_setting_seq2));
0673 
0674     return ret;
0675 }
0676 
0677 static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
0678                 enum cxd2880_dvbt_profile profile)
0679 {
0680     int ret;
0681 
0682     if (!tnr_dmd)
0683         return -EINVAL;
0684 
0685     ret = tnr_dmd->io->write_reg(tnr_dmd->io,
0686                      CXD2880_IO_TGT_DMD,
0687                      0x00, 0x10);
0688     if (ret)
0689         return ret;
0690 
0691     return tnr_dmd->io->write_reg(tnr_dmd->io,
0692                       CXD2880_IO_TGT_DMD,
0693                       0x67,
0694                       (profile == CXD2880_DVBT_PROFILE_HP)
0695                       ? 0x00 : 0x01);
0696 }
0697 
0698 int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
0699                   struct cxd2880_dvbt_tune_param
0700                   *tune_param)
0701 {
0702     int ret;
0703 
0704     if (!tnr_dmd || !tune_param)
0705         return -EINVAL;
0706 
0707     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0708         return -EINVAL;
0709 
0710     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
0711         tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0712         return -EINVAL;
0713 
0714     ret =
0715         cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT,
0716                         tune_param->center_freq_khz,
0717                         tune_param->bandwidth, 0, 0);
0718     if (ret)
0719         return ret;
0720 
0721     ret =
0722         x_tune_dvbt_demod_setting(tnr_dmd, tune_param->bandwidth,
0723                       tnr_dmd->clk_mode);
0724     if (ret)
0725         return ret;
0726 
0727     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
0728         ret =
0729             x_tune_dvbt_demod_setting(tnr_dmd->diver_sub,
0730                           tune_param->bandwidth,
0731                           tnr_dmd->diver_sub->clk_mode);
0732         if (ret)
0733             return ret;
0734     }
0735 
0736     return dvbt_set_profile(tnr_dmd, tune_param->profile);
0737 }
0738 
0739 int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
0740                   struct cxd2880_dvbt_tune_param
0741                   *tune_param)
0742 {
0743     int ret;
0744 
0745     if (!tnr_dmd || !tune_param)
0746         return -EINVAL;
0747 
0748     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0749         return -EINVAL;
0750 
0751     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
0752         tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0753         return -EINVAL;
0754 
0755     ret =
0756         cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, CXD2880_DTV_SYS_DVBT,
0757                         0);
0758     if (ret)
0759         return ret;
0760 
0761     tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;
0762     tnr_dmd->frequency_khz = tune_param->center_freq_khz;
0763     tnr_dmd->sys = CXD2880_DTV_SYS_DVBT;
0764     tnr_dmd->bandwidth = tune_param->bandwidth;
0765 
0766     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {
0767         tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;
0768         tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;
0769         tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT;
0770         tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;
0771     }
0772 
0773     return 0;
0774 }
0775 
0776 int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
0777 {
0778     int ret;
0779 
0780     if (!tnr_dmd)
0781         return -EINVAL;
0782 
0783     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0784         return -EINVAL;
0785 
0786     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
0787         tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0788         return -EINVAL;
0789 
0790     ret = x_sleep_dvbt_demod_setting(tnr_dmd);
0791     if (ret)
0792         return ret;
0793 
0794     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
0795         ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
0796 
0797     return ret;
0798 }
0799 
0800 int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
0801                      *tnr_dmd,
0802                      enum
0803                      cxd2880_tnrdmd_lock_result
0804                      *lock)
0805 {
0806     int ret;
0807 
0808     u8 sync_stat = 0;
0809     u8 ts_lock = 0;
0810     u8 unlock_detected = 0;
0811     u8 unlock_detected_sub = 0;
0812 
0813     if (!tnr_dmd || !lock)
0814         return -EINVAL;
0815 
0816     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0817         return -EINVAL;
0818 
0819     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0820         return -EINVAL;
0821 
0822     ret =
0823         cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
0824                           &unlock_detected);
0825     if (ret)
0826         return ret;
0827 
0828     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
0829         if (sync_stat == 6)
0830             *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
0831         else if (unlock_detected)
0832             *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
0833         else
0834             *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
0835 
0836         return ret;
0837     }
0838 
0839     if (sync_stat == 6) {
0840         *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
0841         return ret;
0842     }
0843 
0844     ret =
0845         cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
0846                           &unlock_detected_sub);
0847     if (ret)
0848         return ret;
0849 
0850     if (sync_stat == 6)
0851         *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
0852     else if (unlock_detected && unlock_detected_sub)
0853         *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
0854     else
0855         *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
0856 
0857     return ret;
0858 }
0859 
0860 int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
0861                       *tnr_dmd,
0862                       enum
0863                       cxd2880_tnrdmd_lock_result
0864                       *lock)
0865 {
0866     int ret;
0867 
0868     u8 sync_stat = 0;
0869     u8 ts_lock = 0;
0870     u8 unlock_detected = 0;
0871     u8 unlock_detected_sub = 0;
0872 
0873     if (!tnr_dmd || !lock)
0874         return -EINVAL;
0875 
0876     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
0877         return -EINVAL;
0878 
0879     if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
0880         return -EINVAL;
0881 
0882     ret =
0883         cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,
0884                           &unlock_detected);
0885     if (ret)
0886         return ret;
0887 
0888     if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
0889         if (ts_lock)
0890             *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
0891         else if (unlock_detected)
0892             *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
0893         else
0894             *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
0895 
0896         return ret;
0897     }
0898 
0899     if (ts_lock) {
0900         *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;
0901         return ret;
0902     } else if (!unlock_detected) {
0903         *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
0904         return ret;
0905     }
0906 
0907     ret =
0908         cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(tnr_dmd, &sync_stat,
0909                           &unlock_detected_sub);
0910     if (ret)
0911         return ret;
0912 
0913     if (unlock_detected && unlock_detected_sub)
0914         *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;
0915     else
0916         *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;
0917 
0918     return ret;
0919 }