linux/drivers/media/dvb-frontends/cxd2880/cxd2880_tnrdmd_dvbt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * cxd2880_tnrdmd_dvbt.c
   4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver
   5 * control functions for DVB-T
   6 *
   7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
   8 */
   9
  10#include <media/dvb_frontend.h>
  11
  12#include "cxd2880_tnrdmd_dvbt.h"
  13#include "cxd2880_tnrdmd_dvbt_mon.h"
  14
  15static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {
  16        {0x00, 0x00}, {0x31, 0x01},
  17};
  18
  19static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {
  20        {0x00, 0x04}, {0x5c, 0xfb}, {0x00, 0x10}, {0xa4, 0x03},
  21        {0x00, 0x14}, {0xb0, 0x00}, {0x00, 0x25},
  22};
  23
  24static const struct cxd2880_reg_value tune_dmd_setting_seq3[] = {
  25        {0x00, 0x12}, {0x44, 0x00},
  26};
  27
  28static const struct cxd2880_reg_value tune_dmd_setting_seq4[] = {
  29        {0x00, 0x11}, {0x87, 0xd2},
  30};
  31
  32static const struct cxd2880_reg_value tune_dmd_setting_seq5[] = {
  33        {0x00, 0x00}, {0xfd, 0x01},
  34};
  35
  36static const struct cxd2880_reg_value sleep_dmd_setting_seq1[] = {
  37        {0x00, 0x04}, {0x5c, 0xd8}, {0x00, 0x10}, {0xa4, 0x00},
  38};
  39
  40static const struct cxd2880_reg_value sleep_dmd_setting_seq2[] = {
  41        {0x00, 0x11}, {0x87, 0x04},
  42};
  43
  44static int x_tune_dvbt_demod_setting(struct cxd2880_tnrdmd
  45                                     *tnr_dmd,
  46                                     enum cxd2880_dtv_bandwidth
  47                                     bandwidth,
  48                                     enum cxd2880_tnrdmd_clockmode
  49                                     clk_mode)
  50{
  51        static const u8 clk_mode_ckffrq_a[2] = { 0x52, 0x49 };
  52        static const u8 clk_mode_ckffrq_b[2] = { 0x5d, 0x55 };
  53        static const u8 clk_mode_ckffrq_c[2] = { 0x60, 0x00 };
  54        static const u8 ratectl_margin[2] = { 0x01, 0xf0 };
  55        static const u8 maxclkcnt_a[3] = { 0x73, 0xca, 0x49 };
  56        static const u8 maxclkcnt_b[3] = { 0xc8, 0x13, 0xaa };
  57        static const u8 maxclkcnt_c[3] = { 0xdc, 0x6c, 0x00 };
  58
  59        static const u8 bw8_nomi_ac[5] = { 0x15, 0x00, 0x00, 0x00, 0x00};
  60        static const u8 bw8_nomi_b[5] = { 0x14, 0x6a, 0xaa, 0xaa, 0xaa};
  61        static const u8 bw8_gtdofst_a[2] = { 0x01, 0x28 };
  62        static const u8 bw8_gtdofst_b[2] = { 0x11, 0x44 };
  63        static const u8 bw8_gtdofst_c[2] = { 0x15, 0x28 };
  64        static const u8 bw8_mrc_a[5] = { 0x30, 0x00, 0x00, 0x90, 0x00 };
  65        static const u8 bw8_mrc_b[5] = { 0x36, 0x71, 0x00, 0xa3, 0x55 };
  66        static const u8 bw8_mrc_c[5] = { 0x38, 0x00, 0x00, 0xa8, 0x00 };
  67        static const u8 bw8_notch[4] = { 0xb3, 0x00, 0x01, 0x02 };
  68
  69        static const u8 bw7_nomi_ac[5] = { 0x18, 0x00, 0x00, 0x00, 0x00};
  70        static const u8 bw7_nomi_b[5] = { 0x17, 0x55, 0x55, 0x55, 0x55};
  71        static const u8 bw7_gtdofst_a[2] = { 0x12, 0x4c };
  72        static const u8 bw7_gtdofst_b[2] = { 0x1f, 0x15 };
  73        static const u8 bw7_gtdofst_c[2] = { 0x1f, 0xf8 };
  74        static const u8 bw7_mrc_a[5] = { 0x36, 0xdb, 0x00, 0xa4, 0x92 };
  75        static const u8 bw7_mrc_b[5] = { 0x3e, 0x38, 0x00, 0xba, 0xaa };
  76        static const u8 bw7_mrc_c[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
  77        static const u8 bw7_notch[4] = { 0xb8, 0x00, 0x00, 0x03 };
  78
  79        static const u8 bw6_nomi_ac[5] = { 0x1c, 0x00, 0x00, 0x00, 0x00};
  80        static const u8 bw6_nomi_b[5] = { 0x1b, 0x38, 0xe3, 0x8e, 0x38};
  81        static const u8 bw6_gtdofst_a[2] = { 0x1f, 0xf8 };
  82        static const u8 bw6_gtdofst_b[2] = { 0x24, 0x43 };
  83        static const u8 bw6_gtdofst_c[2] = { 0x25, 0x4c };
  84        static const u8 bw6_mrc_a[5] = { 0x40, 0x00, 0x00, 0xc0, 0x00 };
  85        static const u8 bw6_mrc_b[5] = { 0x48, 0x97, 0x00, 0xd9, 0xc7 };
  86        static const u8 bw6_mrc_c[5] = { 0x4a, 0xaa, 0x00, 0xdf, 0xff };
  87        static const u8 bw6_notch[4] = { 0xbe, 0xab, 0x00, 0x03 };
  88
  89        static const u8 bw5_nomi_ac[5] = { 0x21, 0x99, 0x99, 0x99, 0x99};
  90        static const u8 bw5_nomi_b[5] = { 0x20, 0xaa, 0xaa, 0xaa, 0xaa};
  91        static const u8 bw5_gtdofst_a[2] = { 0x26, 0x5d };
  92        static const u8 bw5_gtdofst_b[2] = { 0x2b, 0x84 };
  93        static const u8 bw5_gtdofst_c[2] = { 0x2c, 0xc2 };
  94        static const u8 bw5_mrc_a[5] = { 0x4c, 0xcc, 0x00, 0xe6, 0x66 };
  95        static const u8 bw5_mrc_b[5] = { 0x57, 0x1c, 0x01, 0x05, 0x55 };
  96        static const u8 bw5_mrc_c[5] = { 0x59, 0x99, 0x01, 0x0c, 0xcc };
  97        static const u8 bw5_notch[4] = { 0xc8, 0x01, 0x00, 0x03 };
  98        const u8 *data = NULL;
  99        u8 sst_data;
 100        int ret;
 101
 102        if (!tnr_dmd)
 103                return -EINVAL;
 104
 105        ret = cxd2880_io_write_multi_regs(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
 653static int x_sleep_dvbt_demod_setting(struct cxd2880_tnrdmd
 654                                                   *tnr_dmd)
 655{
 656        int ret;
 657
 658        if (!tnr_dmd)
 659                return -EINVAL;
 660
 661        ret = cxd2880_io_write_multi_regs(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
 677static int dvbt_set_profile(struct cxd2880_tnrdmd *tnr_dmd,
 678                            enum cxd2880_dvbt_profile profile)
 679{
 680        int ret;
 681
 682        if (!tnr_dmd)
 683                return -EINVAL;
 684
 685        ret = tnr_dmd->io->write_reg(tnr_dmd->io,
 686                                     CXD2880_IO_TGT_DMD,
 687                                     0x00, 0x10);
 688        if (ret)
 689                return ret;
 690
 691        return tnr_dmd->io->write_reg(tnr_dmd->io,
 692                                      CXD2880_IO_TGT_DMD,
 693                                      0x67,
 694                                      (profile == CXD2880_DVBT_PROFILE_HP)
 695                                      ? 0x00 : 0x01);
 696}
 697
 698int cxd2880_tnrdmd_dvbt_tune1(struct cxd2880_tnrdmd *tnr_dmd,
 699                              struct cxd2880_dvbt_tune_param
 700                              *tune_param)
 701{
 702        int ret;
 703
 704        if (!tnr_dmd || !tune_param)
 705                return -EINVAL;
 706
 707        if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
 708                return -EINVAL;
 709
 710        if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
 711            tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
 712                return -EINVAL;
 713
 714        ret =
 715            cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, 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
 739int cxd2880_tnrdmd_dvbt_tune2(struct cxd2880_tnrdmd *tnr_dmd,
 740                              struct cxd2880_dvbt_tune_param
 741                              *tune_param)
 742{
 743        int ret;
 744
 745        if (!tnr_dmd || !tune_param)
 746                return -EINVAL;
 747
 748        if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
 749                return -EINVAL;
 750
 751        if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
 752            tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
 753                return -EINVAL;
 754
 755        ret =
 756            cxd2880_tnrdmd_common_tune_setting2(tnr_dmd, 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
 776int cxd2880_tnrdmd_dvbt_sleep_setting(struct cxd2880_tnrdmd *tnr_dmd)
 777{
 778        int ret;
 779
 780        if (!tnr_dmd)
 781                return -EINVAL;
 782
 783        if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
 784                return -EINVAL;
 785
 786        if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&
 787            tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
 788                return -EINVAL;
 789
 790        ret = x_sleep_dvbt_demod_setting(tnr_dmd);
 791        if (ret)
 792                return ret;
 793
 794        if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
 795                ret = x_sleep_dvbt_demod_setting(tnr_dmd->diver_sub);
 796
 797        return ret;
 798}
 799
 800int cxd2880_tnrdmd_dvbt_check_demod_lock(struct cxd2880_tnrdmd
 801                                         *tnr_dmd,
 802                                         enum
 803                                         cxd2880_tnrdmd_lock_result
 804                                         *lock)
 805{
 806        int ret;
 807
 808        u8 sync_stat = 0;
 809        u8 ts_lock = 0;
 810        u8 unlock_detected = 0;
 811        u8 unlock_detected_sub = 0;
 812
 813        if (!tnr_dmd || !lock)
 814                return -EINVAL;
 815
 816        if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
 817                return -EINVAL;
 818
 819        if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
 820                return -EINVAL;
 821
 822        ret =
 823            cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &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
 860int cxd2880_tnrdmd_dvbt_check_ts_lock(struct cxd2880_tnrdmd
 861                                      *tnr_dmd,
 862                                      enum
 863                                      cxd2880_tnrdmd_lock_result
 864                                      *lock)
 865{
 866        int ret;
 867
 868        u8 sync_stat = 0;
 869        u8 ts_lock = 0;
 870        u8 unlock_detected = 0;
 871        u8 unlock_detected_sub = 0;
 872
 873        if (!tnr_dmd || !lock)
 874                return -EINVAL;
 875
 876        if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
 877                return -EINVAL;
 878
 879        if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
 880                return -EINVAL;
 881
 882        ret =
 883            cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync_stat, &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}
 920