1218 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * cxd2880_tnrdmd_dvbt2.c4 * Sony CXD2880 DVB-T2/T tuner + demodulator driver5 * control functions for DVB-T26 *7 * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation8 */9 10#include <media/dvb_frontend.h>11 12#include "cxd2880_tnrdmd_dvbt2.h"13#include "cxd2880_tnrdmd_dvbt2_mon.h"14 15static const struct cxd2880_reg_value tune_dmd_setting_seq1[] = {16 {0x00, 0x00}, {0x31, 0x02},17};18 19static const struct cxd2880_reg_value tune_dmd_setting_seq2[] = {20 {0x00, 0x04}, {0x5d, 0x0b},21};22 23static int x_tune_dvbt2_demod_setting(struct cxd2880_tnrdmd24 *tnr_dmd,25 enum cxd2880_dtv_bandwidth26 bandwidth,27 enum cxd2880_tnrdmd_clockmode28 clk_mode)29{30 static const u8 tsif_settings[2] = { 0x01, 0x01 };31 static const u8 init_settings[14] = {32 0x07, 0x06, 0x01, 0xf0, 0x00, 0x00, 0x04, 0xb0, 0x00, 0x00,33 0x09, 0x9c, 0x0e, 0x4c34 };35 static const u8 clk_mode_settings_a1[9] = {36 0x52, 0x49, 0x2c, 0x51, 0x51, 0x3d, 0x15, 0x29, 0x0c37 };38 39 static const u8 clk_mode_settings_b1[9] = {40 0x5d, 0x55, 0x32, 0x5c, 0x5c, 0x45, 0x17, 0x2e, 0x0d41 };42 43 static const u8 clk_mode_settings_c1[9] = {44 0x60, 0x00, 0x34, 0x5e, 0x5e, 0x47, 0x18, 0x2f, 0x0e45 };46 47 static const u8 clk_mode_settings_a2[13] = {48 0x04, 0xe7, 0x94, 0x92, 0x09, 0xcf, 0x7e, 0xd0, 0x49,49 0xcd, 0xcd, 0x1f, 0x5b50 };51 52 static const u8 clk_mode_settings_b2[13] = {53 0x05, 0x90, 0x27, 0x55, 0x0b, 0x20, 0x8f, 0xd6, 0xea,54 0xc8, 0xc8, 0x23, 0x9155 };56 57 static const u8 clk_mode_settings_c2[13] = {58 0x05, 0xb8, 0xd8, 0x00, 0x0b, 0x72, 0x93, 0xf3, 0x00,59 0xcd, 0xcd, 0x24, 0x9560 };61 62 static const u8 clk_mode_settings_a3[5] = {63 0x0b, 0x6a, 0xc9, 0x03, 0x3364 };65 static const u8 clk_mode_settings_b3[5] = {66 0x01, 0x02, 0xe4, 0x03, 0x3967 };68 static const u8 clk_mode_settings_c3[5] = {69 0x01, 0x02, 0xeb, 0x03, 0x3b70 };71 72 static const u8 gtdofst[2] = { 0x3f, 0xff };73 74 static const u8 bw8_gtdofst_a[2] = { 0x19, 0xd2 };75 static const u8 bw8_nomi_ac[6] = { 0x15, 0x00, 0x00, 0x00, 0x00, 0x00 };76 static const u8 bw8_nomi_b[6] = { 0x14, 0x6a, 0xaa, 0xaa, 0xab, 0x00 };77 static const u8 bw8_sst_a[2] = { 0x06, 0x2a };78 static const u8 bw8_sst_b[2] = { 0x06, 0x29 };79 static const u8 bw8_sst_c[2] = { 0x06, 0x28 };80 static const u8 bw8_mrc_a[9] = {81 0x28, 0x00, 0x50, 0x00, 0x60, 0x00, 0x00, 0x90, 0x0082 };83 static const u8 bw8_mrc_b[9] = {84 0x2d, 0x5e, 0x5a, 0xbd, 0x6c, 0xe3, 0x00, 0xa3, 0x5585 };86 static const u8 bw8_mrc_c[9] = {87 0x2e, 0xaa, 0x5d, 0x55, 0x70, 0x00, 0x00, 0xa8, 0x0088 };89 90 static const u8 bw7_nomi_ac[6] = { 0x18, 0x00, 0x00, 0x00, 0x00, 0x00 };91 static const u8 bw7_nomi_b[6] = { 0x17, 0x55, 0x55, 0x55, 0x55, 0x00 };92 static const u8 bw7_sst_a[2] = { 0x06, 0x23 };93 static const u8 bw7_sst_b[2] = { 0x06, 0x22 };94 static const u8 bw7_sst_c[2] = { 0x06, 0x21 };95 static const u8 bw7_mrc_a[9] = {96 0x2d, 0xb6, 0x5b, 0x6d, 0x6d, 0xb6, 0x00, 0xa4, 0x9297 };98 static const u8 bw7_mrc_b[9] = {99 0x33, 0xda, 0x67, 0xb4, 0x7c, 0x71, 0x00, 0xba, 0xaa100 };101 static const u8 bw7_mrc_c[9] = {102 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00103 };104 105 static const u8 bw6_nomi_ac[6] = { 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00 };106 static const u8 bw6_nomi_b[6] = { 0x1b, 0x38, 0xe3, 0x8e, 0x39, 0x00 };107 static const u8 bw6_sst_a[2] = { 0x06, 0x1c };108 static const u8 bw6_sst_b[2] = { 0x06, 0x1b };109 static const u8 bw6_sst_c[2] = { 0x06, 0x1a };110 static const u8 bw6_mrc_a[9] = {111 0x35, 0x55, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xc0, 0x00112 };113 static const u8 bw6_mrc_b[9] = {114 0x3c, 0x7e, 0x78, 0xfc, 0x91, 0x2f, 0x00, 0xd9, 0xc7115 };116 static const u8 bw6_mrc_c[9] = {117 0x3e, 0x38, 0x7c, 0x71, 0x95, 0x55, 0x00, 0xdf, 0xff118 };119 120 static const u8 bw5_nomi_ac[6] = { 0x21, 0x99, 0x99, 0x99, 0x9a, 0x00 };121 static const u8 bw5_nomi_b[6] = { 0x20, 0xaa, 0xaa, 0xaa, 0xab, 0x00 };122 static const u8 bw5_sst_a[2] = { 0x06, 0x15 };123 static const u8 bw5_sst_b[2] = { 0x06, 0x15 };124 static const u8 bw5_sst_c[2] = { 0x06, 0x14 };125 static const u8 bw5_mrc_a[9] = {126 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x00, 0xe6, 0x66127 };128 static const u8 bw5_mrc_b[9] = {129 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x01, 0x05, 0x55130 };131 static const u8 bw5_mrc_c[9] = {132 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x01, 0x0c, 0xcc133 };134 135 static const u8 bw1_7_nomi_a[6] = {136 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03137 };138 static const u8 bw1_7_nomi_c[6] = {139 0x68, 0x0f, 0xa2, 0x32, 0xcf, 0x03140 };141 static const u8 bw1_7_nomi_b[6] = {142 0x65, 0x2b, 0xa4, 0xcd, 0xd8, 0x03143 };144 static const u8 bw1_7_sst_a[2] = { 0x06, 0x0c };145 static const u8 bw1_7_sst_b[2] = { 0x06, 0x0c };146 static const u8 bw1_7_sst_c[2] = { 0x06, 0x0b };147 static const u8 bw1_7_mrc_a[9] = {148 0x40, 0x00, 0x6a, 0xaa, 0x80, 0x00, 0x02, 0xc9, 0x8f149 };150 static const u8 bw1_7_mrc_b[9] = {151 0x48, 0x97, 0x78, 0xfc, 0x91, 0x2f, 0x03, 0x29, 0x5d152 };153 static const u8 bw1_7_mrc_c[9] = {154 0x4a, 0xaa, 0x7c, 0x71, 0x95, 0x55, 0x03, 0x40, 0x7d155 };156 157 const u8 *data = NULL;158 const u8 *data2 = NULL;159 const u8 *data3 = NULL;160 int ret;161 162 if (!tnr_dmd)163 return -EINVAL;164 165 ret = cxd2880_io_write_multi_regs(tnr_dmd->io,166 CXD2880_IO_TGT_SYS,167 tune_dmd_setting_seq1,168 ARRAY_SIZE(tune_dmd_setting_seq1));169 if (ret)170 return ret;171 172 ret = cxd2880_io_write_multi_regs(tnr_dmd->io,173 CXD2880_IO_TGT_DMD,174 tune_dmd_setting_seq2,175 ARRAY_SIZE(tune_dmd_setting_seq2));176 if (ret)177 return ret;178 179 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {180 ret = tnr_dmd->io->write_reg(tnr_dmd->io,181 CXD2880_IO_TGT_DMD,182 0x00, 0x00);183 if (ret)184 return ret;185 186 ret = tnr_dmd->io->write_regs(tnr_dmd->io,187 CXD2880_IO_TGT_DMD,188 0xce, tsif_settings, 2);189 if (ret)190 return ret;191 }192 193 ret = tnr_dmd->io->write_reg(tnr_dmd->io,194 CXD2880_IO_TGT_DMD,195 0x00, 0x20);196 if (ret)197 return ret;198 199 ret = tnr_dmd->io->write_reg(tnr_dmd->io,200 CXD2880_IO_TGT_DMD,201 0x8a, init_settings[0]);202 if (ret)203 return ret;204 205 ret = tnr_dmd->io->write_reg(tnr_dmd->io,206 CXD2880_IO_TGT_DMD,207 0x90, init_settings[1]);208 if (ret)209 return ret;210 211 ret = tnr_dmd->io->write_reg(tnr_dmd->io,212 CXD2880_IO_TGT_DMD,213 0x00, 0x25);214 if (ret)215 return ret;216 217 ret = tnr_dmd->io->write_regs(tnr_dmd->io,218 CXD2880_IO_TGT_DMD,219 0xf0, &init_settings[2], 2);220 if (ret)221 return ret;222 223 ret = tnr_dmd->io->write_reg(tnr_dmd->io,224 CXD2880_IO_TGT_DMD,225 0x00, 0x2a);226 if (ret)227 return ret;228 229 ret = tnr_dmd->io->write_reg(tnr_dmd->io,230 CXD2880_IO_TGT_DMD,231 0xdc, init_settings[4]);232 if (ret)233 return ret;234 235 ret = tnr_dmd->io->write_reg(tnr_dmd->io,236 CXD2880_IO_TGT_DMD,237 0xde, init_settings[5]);238 if (ret)239 return ret;240 241 ret = tnr_dmd->io->write_reg(tnr_dmd->io,242 CXD2880_IO_TGT_DMD,243 0x00, 0x2d);244 if (ret)245 return ret;246 247 ret = tnr_dmd->io->write_regs(tnr_dmd->io,248 CXD2880_IO_TGT_DMD,249 0x73, &init_settings[6], 4);250 if (ret)251 return ret;252 253 ret = tnr_dmd->io->write_regs(tnr_dmd->io,254 CXD2880_IO_TGT_DMD,255 0x8f, &init_settings[10], 4);256 if (ret)257 return ret;258 259 switch (clk_mode) {260 case CXD2880_TNRDMD_CLOCKMODE_A:261 data = clk_mode_settings_a1;262 data2 = clk_mode_settings_a2;263 data3 = clk_mode_settings_a3;264 break;265 case CXD2880_TNRDMD_CLOCKMODE_B:266 data = clk_mode_settings_b1;267 data2 = clk_mode_settings_b2;268 data3 = clk_mode_settings_b3;269 break;270 case CXD2880_TNRDMD_CLOCKMODE_C:271 data = clk_mode_settings_c1;272 data2 = clk_mode_settings_c2;273 data3 = clk_mode_settings_c3;274 break;275 default:276 return -EINVAL;277 }278 279 ret = tnr_dmd->io->write_reg(tnr_dmd->io,280 CXD2880_IO_TGT_DMD,281 0x00, 0x04);282 if (ret)283 return ret;284 285 ret = tnr_dmd->io->write_regs(tnr_dmd->io,286 CXD2880_IO_TGT_DMD,287 0x1d, &data[0], 3);288 if (ret)289 return ret;290 291 ret = tnr_dmd->io->write_reg(tnr_dmd->io,292 CXD2880_IO_TGT_DMD,293 0x22, data[3]);294 if (ret)295 return ret;296 297 ret = tnr_dmd->io->write_reg(tnr_dmd->io,298 CXD2880_IO_TGT_DMD,299 0x24, data[4]);300 if (ret)301 return ret;302 303 ret = tnr_dmd->io->write_reg(tnr_dmd->io,304 CXD2880_IO_TGT_DMD,305 0x26, data[5]);306 if (ret)307 return ret;308 309 ret = tnr_dmd->io->write_regs(tnr_dmd->io,310 CXD2880_IO_TGT_DMD,311 0x29, &data[6], 2);312 if (ret)313 return ret;314 315 ret = tnr_dmd->io->write_reg(tnr_dmd->io,316 CXD2880_IO_TGT_DMD,317 0x2d, data[8]);318 if (ret)319 return ret;320 321 if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_SUB) {322 ret = tnr_dmd->io->write_regs(tnr_dmd->io,323 CXD2880_IO_TGT_DMD,324 0x2e, &data2[0], 6);325 if (ret)326 return ret;327 328 ret = tnr_dmd->io->write_regs(tnr_dmd->io,329 CXD2880_IO_TGT_DMD,330 0x35, &data2[6], 7);331 if (ret)332 return ret;333 }334 335 ret = tnr_dmd->io->write_regs(tnr_dmd->io,336 CXD2880_IO_TGT_DMD,337 0x3c, &data3[0], 2);338 if (ret)339 return ret;340 341 ret = tnr_dmd->io->write_regs(tnr_dmd->io,342 CXD2880_IO_TGT_DMD,343 0x56, &data3[2], 3);344 if (ret)345 return ret;346 347 switch (bandwidth) {348 case CXD2880_DTV_BW_8_MHZ:349 switch (clk_mode) {350 case CXD2880_TNRDMD_CLOCKMODE_A:351 case CXD2880_TNRDMD_CLOCKMODE_C:352 data = bw8_nomi_ac;353 break;354 case CXD2880_TNRDMD_CLOCKMODE_B:355 data = bw8_nomi_b;356 break;357 default:358 return -EINVAL;359 }360 361 ret = tnr_dmd->io->write_regs(tnr_dmd->io,362 CXD2880_IO_TGT_DMD,363 0x10, data, 6);364 if (ret)365 return ret;366 367 ret = tnr_dmd->io->write_reg(tnr_dmd->io,368 CXD2880_IO_TGT_DMD,369 0x4a, 0x00);370 if (ret)371 return ret;372 373 switch (clk_mode) {374 case CXD2880_TNRDMD_CLOCKMODE_A:375 data = bw8_gtdofst_a;376 break;377 case CXD2880_TNRDMD_CLOCKMODE_B:378 case CXD2880_TNRDMD_CLOCKMODE_C:379 data = gtdofst;380 break;381 default:382 return -EINVAL;383 }384 385 ret = tnr_dmd->io->write_regs(tnr_dmd->io,386 CXD2880_IO_TGT_DMD,387 0x19, data, 2);388 if (ret)389 return ret;390 391 switch (clk_mode) {392 case CXD2880_TNRDMD_CLOCKMODE_A:393 data = bw8_sst_a;394 break;395 case CXD2880_TNRDMD_CLOCKMODE_B:396 data = bw8_sst_b;397 break;398 case CXD2880_TNRDMD_CLOCKMODE_C:399 data = bw8_sst_c;400 break;401 default:402 return -EINVAL;403 }404 405 ret = tnr_dmd->io->write_regs(tnr_dmd->io,406 CXD2880_IO_TGT_DMD,407 0x1b, data, 2);408 if (ret)409 return ret;410 411 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {412 switch (clk_mode) {413 case CXD2880_TNRDMD_CLOCKMODE_A:414 data = bw8_mrc_a;415 break;416 case CXD2880_TNRDMD_CLOCKMODE_B:417 data = bw8_mrc_b;418 break;419 case CXD2880_TNRDMD_CLOCKMODE_C:420 data = bw8_mrc_c;421 break;422 default:423 return -EINVAL;424 }425 426 ret = tnr_dmd->io->write_regs(tnr_dmd->io,427 CXD2880_IO_TGT_DMD,428 0x4b, data, 9);429 if (ret)430 return ret;431 }432 break;433 434 case CXD2880_DTV_BW_7_MHZ:435 switch (clk_mode) {436 case CXD2880_TNRDMD_CLOCKMODE_A:437 case CXD2880_TNRDMD_CLOCKMODE_C:438 data = bw7_nomi_ac;439 break;440 case CXD2880_TNRDMD_CLOCKMODE_B:441 data = bw7_nomi_b;442 break;443 default:444 return -EINVAL;445 }446 447 ret = tnr_dmd->io->write_regs(tnr_dmd->io,448 CXD2880_IO_TGT_DMD,449 0x10, data, 6);450 if (ret)451 return ret;452 453 ret = tnr_dmd->io->write_reg(tnr_dmd->io,454 CXD2880_IO_TGT_DMD,455 0x4a, 0x02);456 if (ret)457 return ret;458 459 ret = tnr_dmd->io->write_regs(tnr_dmd->io,460 CXD2880_IO_TGT_DMD,461 0x19, gtdofst, 2);462 if (ret)463 return ret;464 465 switch (clk_mode) {466 case CXD2880_TNRDMD_CLOCKMODE_A:467 data = bw7_sst_a;468 break;469 case CXD2880_TNRDMD_CLOCKMODE_B:470 data = bw7_sst_b;471 break;472 case CXD2880_TNRDMD_CLOCKMODE_C:473 data = bw7_sst_c;474 break;475 default:476 return -EINVAL;477 }478 479 ret = tnr_dmd->io->write_regs(tnr_dmd->io,480 CXD2880_IO_TGT_DMD,481 0x1b, data, 2);482 if (ret)483 return ret;484 485 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {486 switch (clk_mode) {487 case CXD2880_TNRDMD_CLOCKMODE_A:488 data = bw7_mrc_a;489 break;490 case CXD2880_TNRDMD_CLOCKMODE_B:491 data = bw7_mrc_b;492 break;493 case CXD2880_TNRDMD_CLOCKMODE_C:494 data = bw7_mrc_c;495 break;496 default:497 return -EINVAL;498 }499 500 ret = tnr_dmd->io->write_regs(tnr_dmd->io,501 CXD2880_IO_TGT_DMD,502 0x4b, data, 9);503 if (ret)504 return ret;505 }506 break;507 508 case CXD2880_DTV_BW_6_MHZ:509 switch (clk_mode) {510 case CXD2880_TNRDMD_CLOCKMODE_A:511 case CXD2880_TNRDMD_CLOCKMODE_C:512 data = bw6_nomi_ac;513 break;514 case CXD2880_TNRDMD_CLOCKMODE_B:515 data = bw6_nomi_b;516 break;517 default:518 return -EINVAL;519 }520 521 ret = tnr_dmd->io->write_regs(tnr_dmd->io,522 CXD2880_IO_TGT_DMD,523 0x10, data, 6);524 if (ret)525 return ret;526 527 ret = tnr_dmd->io->write_reg(tnr_dmd->io,528 CXD2880_IO_TGT_DMD,529 0x4a, 0x04);530 if (ret)531 return ret;532 533 ret = tnr_dmd->io->write_regs(tnr_dmd->io,534 CXD2880_IO_TGT_DMD,535 0x19, gtdofst, 2);536 if (ret)537 return ret;538 539 switch (clk_mode) {540 case CXD2880_TNRDMD_CLOCKMODE_A:541 data = bw6_sst_a;542 break;543 case CXD2880_TNRDMD_CLOCKMODE_B:544 data = bw6_sst_b;545 break;546 case CXD2880_TNRDMD_CLOCKMODE_C:547 data = bw6_sst_c;548 break;549 default:550 return -EINVAL;551 }552 553 ret = tnr_dmd->io->write_regs(tnr_dmd->io,554 CXD2880_IO_TGT_DMD,555 0x1b, data, 2);556 if (ret)557 return ret;558 559 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {560 switch (clk_mode) {561 case CXD2880_TNRDMD_CLOCKMODE_A:562 data = bw6_mrc_a;563 break;564 case CXD2880_TNRDMD_CLOCKMODE_B:565 data = bw6_mrc_b;566 break;567 case CXD2880_TNRDMD_CLOCKMODE_C:568 data = bw6_mrc_c;569 break;570 default:571 return -EINVAL;572 }573 574 ret = tnr_dmd->io->write_regs(tnr_dmd->io,575 CXD2880_IO_TGT_DMD,576 0x4b, data, 9);577 if (ret)578 return ret;579 }580 break;581 582 case CXD2880_DTV_BW_5_MHZ:583 switch (clk_mode) {584 case CXD2880_TNRDMD_CLOCKMODE_A:585 case CXD2880_TNRDMD_CLOCKMODE_C:586 data = bw5_nomi_ac;587 break;588 case CXD2880_TNRDMD_CLOCKMODE_B:589 data = bw5_nomi_b;590 break;591 default:592 return -EINVAL;593 }594 595 ret = tnr_dmd->io->write_regs(tnr_dmd->io,596 CXD2880_IO_TGT_DMD,597 0x10, data, 6);598 if (ret)599 return ret;600 601 ret = tnr_dmd->io->write_reg(tnr_dmd->io,602 CXD2880_IO_TGT_DMD,603 0x4a, 0x06);604 if (ret)605 return ret;606 607 ret = tnr_dmd->io->write_regs(tnr_dmd->io,608 CXD2880_IO_TGT_DMD,609 0x19, gtdofst, 2);610 if (ret)611 return ret;612 613 switch (clk_mode) {614 case CXD2880_TNRDMD_CLOCKMODE_A:615 data = bw5_sst_a;616 break;617 case CXD2880_TNRDMD_CLOCKMODE_B:618 data = bw5_sst_b;619 break;620 case CXD2880_TNRDMD_CLOCKMODE_C:621 data = bw5_sst_c;622 break;623 default:624 return -EINVAL;625 }626 627 ret = tnr_dmd->io->write_regs(tnr_dmd->io,628 CXD2880_IO_TGT_DMD,629 0x1b, data, 2);630 if (ret)631 return ret;632 633 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {634 switch (clk_mode) {635 case CXD2880_TNRDMD_CLOCKMODE_A:636 data = bw5_mrc_a;637 break;638 case CXD2880_TNRDMD_CLOCKMODE_B:639 data = bw5_mrc_b;640 break;641 case CXD2880_TNRDMD_CLOCKMODE_C:642 data = bw5_mrc_c;643 break;644 default:645 return -EINVAL;646 }647 648 ret = tnr_dmd->io->write_regs(tnr_dmd->io,649 CXD2880_IO_TGT_DMD,650 0x4b, data, 9);651 if (ret)652 return ret;653 }654 break;655 656 case CXD2880_DTV_BW_1_7_MHZ:657 658 switch (clk_mode) {659 case CXD2880_TNRDMD_CLOCKMODE_A:660 data = bw1_7_nomi_a;661 break;662 case CXD2880_TNRDMD_CLOCKMODE_C:663 data = bw1_7_nomi_c;664 break;665 case CXD2880_TNRDMD_CLOCKMODE_B:666 data = bw1_7_nomi_b;667 break;668 default:669 return -EINVAL;670 }671 672 ret = tnr_dmd->io->write_regs(tnr_dmd->io,673 CXD2880_IO_TGT_DMD,674 0x10, data, 6);675 if (ret)676 return ret;677 678 ret = tnr_dmd->io->write_reg(tnr_dmd->io,679 CXD2880_IO_TGT_DMD,680 0x4a, 0x03);681 if (ret)682 return ret;683 684 ret = tnr_dmd->io->write_regs(tnr_dmd->io,685 CXD2880_IO_TGT_DMD,686 0x19, gtdofst, 2);687 if (ret)688 return ret;689 690 switch (clk_mode) {691 case CXD2880_TNRDMD_CLOCKMODE_A:692 data = bw1_7_sst_a;693 break;694 case CXD2880_TNRDMD_CLOCKMODE_B:695 data = bw1_7_sst_b;696 break;697 case CXD2880_TNRDMD_CLOCKMODE_C:698 data = bw1_7_sst_c;699 break;700 default:701 return -EINVAL;702 }703 704 ret = tnr_dmd->io->write_regs(tnr_dmd->io,705 CXD2880_IO_TGT_DMD,706 0x1b, data, 2);707 if (ret)708 return ret;709 710 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {711 switch (clk_mode) {712 case CXD2880_TNRDMD_CLOCKMODE_A:713 data = bw1_7_mrc_a;714 break;715 case CXD2880_TNRDMD_CLOCKMODE_B:716 data = bw1_7_mrc_b;717 break;718 case CXD2880_TNRDMD_CLOCKMODE_C:719 data = bw1_7_mrc_c;720 break;721 default:722 return -EINVAL;723 }724 725 ret = tnr_dmd->io->write_regs(tnr_dmd->io,726 CXD2880_IO_TGT_DMD,727 0x4b, data, 9);728 if (ret)729 return ret;730 }731 break;732 733 default:734 return -EINVAL;735 }736 737 ret = tnr_dmd->io->write_reg(tnr_dmd->io,738 CXD2880_IO_TGT_DMD,739 0x00, 0x00);740 if (ret)741 return ret;742 743 return tnr_dmd->io->write_reg(tnr_dmd->io,744 CXD2880_IO_TGT_DMD,745 0xfd, 0x01);746}747 748static int x_sleep_dvbt2_demod_setting(struct cxd2880_tnrdmd749 *tnr_dmd)750{751 static const u8 difint_clip[] = {752 0, 1, 0, 2, 0, 4, 0, 8, 0, 16, 0, 32753 };754 int ret = 0;755 756 if (!tnr_dmd)757 return -EINVAL;758 759 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {760 ret = tnr_dmd->io->write_reg(tnr_dmd->io,761 CXD2880_IO_TGT_DMD,762 0x00, 0x1d);763 if (ret)764 return ret;765 766 ret = tnr_dmd->io->write_regs(tnr_dmd->io,767 CXD2880_IO_TGT_DMD,768 0x47, difint_clip, 12);769 }770 771 return ret;772}773 774static int dvbt2_set_profile(struct cxd2880_tnrdmd *tnr_dmd,775 enum cxd2880_dvbt2_profile profile)776{777 u8 t2_mode_tune_mode = 0;778 u8 seq_not2_dtime = 0;779 u8 dtime1 = 0;780 u8 dtime2 = 0;781 int ret;782 783 if (!tnr_dmd)784 return -EINVAL;785 786 switch (tnr_dmd->clk_mode) {787 case CXD2880_TNRDMD_CLOCKMODE_A:788 dtime1 = 0x27;789 dtime2 = 0x0c;790 break;791 case CXD2880_TNRDMD_CLOCKMODE_B:792 dtime1 = 0x2c;793 dtime2 = 0x0d;794 break;795 case CXD2880_TNRDMD_CLOCKMODE_C:796 dtime1 = 0x2e;797 dtime2 = 0x0e;798 break;799 default:800 return -EINVAL;801 }802 803 switch (profile) {804 case CXD2880_DVBT2_PROFILE_BASE:805 t2_mode_tune_mode = 0x01;806 seq_not2_dtime = dtime2;807 break;808 809 case CXD2880_DVBT2_PROFILE_LITE:810 t2_mode_tune_mode = 0x05;811 seq_not2_dtime = dtime1;812 break;813 814 case CXD2880_DVBT2_PROFILE_ANY:815 t2_mode_tune_mode = 0x00;816 seq_not2_dtime = dtime1;817 break;818 819 default:820 return -EINVAL;821 }822 823 ret = tnr_dmd->io->write_reg(tnr_dmd->io,824 CXD2880_IO_TGT_DMD,825 0x00, 0x2e);826 if (ret)827 return ret;828 829 ret = tnr_dmd->io->write_reg(tnr_dmd->io,830 CXD2880_IO_TGT_DMD,831 0x10, t2_mode_tune_mode);832 if (ret)833 return ret;834 835 ret = tnr_dmd->io->write_reg(tnr_dmd->io,836 CXD2880_IO_TGT_DMD,837 0x00, 0x04);838 if (ret)839 return ret;840 841 return tnr_dmd->io->write_reg(tnr_dmd->io,842 CXD2880_IO_TGT_DMD,843 0x2c, seq_not2_dtime);844}845 846int cxd2880_tnrdmd_dvbt2_tune1(struct cxd2880_tnrdmd *tnr_dmd,847 struct cxd2880_dvbt2_tune_param848 *tune_param)849{850 int ret;851 852 if (!tnr_dmd || !tune_param)853 return -EINVAL;854 855 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)856 return -EINVAL;857 858 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&859 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)860 return -EINVAL;861 862 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN &&863 tune_param->profile == CXD2880_DVBT2_PROFILE_ANY)864 return -ENOTTY;865 866 ret =867 cxd2880_tnrdmd_common_tune_setting1(tnr_dmd, CXD2880_DTV_SYS_DVBT2,868 tune_param->center_freq_khz,869 tune_param->bandwidth, 0, 0);870 if (ret)871 return ret;872 873 ret =874 x_tune_dvbt2_demod_setting(tnr_dmd, tune_param->bandwidth,875 tnr_dmd->clk_mode);876 if (ret)877 return ret;878 879 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {880 ret =881 x_tune_dvbt2_demod_setting(tnr_dmd->diver_sub,882 tune_param->bandwidth,883 tnr_dmd->diver_sub->clk_mode);884 if (ret)885 return ret;886 }887 888 ret = dvbt2_set_profile(tnr_dmd, tune_param->profile);889 if (ret)890 return ret;891 892 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {893 ret =894 dvbt2_set_profile(tnr_dmd->diver_sub, tune_param->profile);895 if (ret)896 return ret;897 }898 899 if (tune_param->data_plp_id == CXD2880_DVBT2_TUNE_PARAM_PLPID_AUTO)900 ret = cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 1, 0);901 else902 ret =903 cxd2880_tnrdmd_dvbt2_set_plp_cfg(tnr_dmd, 0,904 (u8)(tune_param->data_plp_id));905 906 return ret;907}908 909int cxd2880_tnrdmd_dvbt2_tune2(struct cxd2880_tnrdmd *tnr_dmd,910 struct cxd2880_dvbt2_tune_param911 *tune_param)912{913 u8 en_fef_intmtnt_ctrl = 1;914 int ret;915 916 if (!tnr_dmd || !tune_param)917 return -EINVAL;918 919 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)920 return -EINVAL;921 922 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&923 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)924 return -EINVAL;925 926 switch (tune_param->profile) {927 case CXD2880_DVBT2_PROFILE_BASE:928 en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_base;929 break;930 case CXD2880_DVBT2_PROFILE_LITE:931 en_fef_intmtnt_ctrl = tnr_dmd->en_fef_intmtnt_lite;932 break;933 case CXD2880_DVBT2_PROFILE_ANY:934 if (tnr_dmd->en_fef_intmtnt_base &&935 tnr_dmd->en_fef_intmtnt_lite)936 en_fef_intmtnt_ctrl = 1;937 else938 en_fef_intmtnt_ctrl = 0;939 break;940 default:941 return -EINVAL;942 }943 944 ret =945 cxd2880_tnrdmd_common_tune_setting2(tnr_dmd,946 CXD2880_DTV_SYS_DVBT2,947 en_fef_intmtnt_ctrl);948 if (ret)949 return ret;950 951 tnr_dmd->state = CXD2880_TNRDMD_STATE_ACTIVE;952 tnr_dmd->frequency_khz = tune_param->center_freq_khz;953 tnr_dmd->sys = CXD2880_DTV_SYS_DVBT2;954 tnr_dmd->bandwidth = tune_param->bandwidth;955 956 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN) {957 tnr_dmd->diver_sub->state = CXD2880_TNRDMD_STATE_ACTIVE;958 tnr_dmd->diver_sub->frequency_khz = tune_param->center_freq_khz;959 tnr_dmd->diver_sub->sys = CXD2880_DTV_SYS_DVBT2;960 tnr_dmd->diver_sub->bandwidth = tune_param->bandwidth;961 }962 963 return 0;964}965 966int cxd2880_tnrdmd_dvbt2_sleep_setting(struct cxd2880_tnrdmd967 *tnr_dmd)968{969 int ret;970 971 if (!tnr_dmd)972 return -EINVAL;973 974 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)975 return -EINVAL;976 977 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&978 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)979 return -EINVAL;980 981 ret = x_sleep_dvbt2_demod_setting(tnr_dmd);982 if (ret)983 return ret;984 985 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)986 ret = x_sleep_dvbt2_demod_setting(tnr_dmd->diver_sub);987 988 return ret;989}990 991int cxd2880_tnrdmd_dvbt2_check_demod_lock(struct cxd2880_tnrdmd992 *tnr_dmd,993 enum994 cxd2880_tnrdmd_lock_result995 *lock)996{997 int ret;998 999 u8 sync_stat = 0;1000 u8 ts_lock = 0;1001 u8 unlock_detected = 0;1002 u8 unlock_detected_sub = 0;1003 1004 if (!tnr_dmd || !lock)1005 return -EINVAL;1006 1007 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)1008 return -EINVAL;1009 1010 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)1011 return -EINVAL;1012 1013 ret =1014 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,1015 &unlock_detected);1016 if (ret)1017 return ret;1018 1019 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {1020 if (sync_stat == 6)1021 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;1022 else if (unlock_detected)1023 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;1024 else1025 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;1026 1027 return 0;1028 }1029 1030 if (sync_stat == 6) {1031 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;1032 return 0;1033 }1034 1035 ret =1036 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,1037 &unlock_detected_sub);1038 if (ret)1039 return ret;1040 1041 if (sync_stat == 6)1042 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;1043 else if (unlock_detected && unlock_detected_sub)1044 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;1045 else1046 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;1047 1048 return 0;1049}1050 1051int cxd2880_tnrdmd_dvbt2_check_ts_lock(struct cxd2880_tnrdmd1052 *tnr_dmd,1053 enum1054 cxd2880_tnrdmd_lock_result1055 *lock)1056{1057 int ret;1058 1059 u8 sync_stat = 0;1060 u8 ts_lock = 0;1061 u8 unlock_detected = 0;1062 u8 unlock_detected_sub = 0;1063 1064 if (!tnr_dmd || !lock)1065 return -EINVAL;1066 1067 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)1068 return -EINVAL;1069 1070 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)1071 return -EINVAL;1072 1073 ret =1074 cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd, &sync_stat, &ts_lock,1075 &unlock_detected);1076 if (ret)1077 return ret;1078 1079 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {1080 if (ts_lock)1081 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;1082 else if (unlock_detected)1083 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;1084 else1085 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;1086 1087 return 0;1088 }1089 1090 if (ts_lock) {1091 *lock = CXD2880_TNRDMD_LOCK_RESULT_LOCKED;1092 return 0;1093 } else if (!unlock_detected) {1094 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;1095 return 0;1096 }1097 1098 ret =1099 cxd2880_tnrdmd_dvbt2_mon_sync_stat_sub(tnr_dmd, &sync_stat,1100 &unlock_detected_sub);1101 if (ret)1102 return ret;1103 1104 if (unlock_detected && unlock_detected_sub)1105 *lock = CXD2880_TNRDMD_LOCK_RESULT_UNLOCKED;1106 else1107 *lock = CXD2880_TNRDMD_LOCK_RESULT_NOTDETECT;1108 1109 return 0;1110}1111 1112int cxd2880_tnrdmd_dvbt2_set_plp_cfg(struct cxd2880_tnrdmd1113 *tnr_dmd, u8 auto_plp,1114 u8 plp_id)1115{1116 int ret;1117 1118 if (!tnr_dmd)1119 return -EINVAL;1120 1121 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)1122 return -EINVAL;1123 1124 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&1125 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)1126 return -EINVAL;1127 1128 ret = tnr_dmd->io->write_reg(tnr_dmd->io,1129 CXD2880_IO_TGT_DMD,1130 0x00, 0x23);1131 if (ret)1132 return ret;1133 1134 if (!auto_plp) {1135 ret = tnr_dmd->io->write_reg(tnr_dmd->io,1136 CXD2880_IO_TGT_DMD,1137 0xaf, plp_id);1138 if (ret)1139 return ret;1140 }1141 1142 return tnr_dmd->io->write_reg(tnr_dmd->io,1143 CXD2880_IO_TGT_DMD,1144 0xad, auto_plp ? 0x00 : 0x01);1145}1146 1147int cxd2880_tnrdmd_dvbt2_diver_fef_setting(struct cxd2880_tnrdmd1148 *tnr_dmd)1149{1150 struct cxd2880_dvbt2_ofdm ofdm;1151 static const u8 data[] = { 0, 8, 0, 16, 0, 32, 0, 64, 0, 128, 1, 0};1152 int ret;1153 1154 if (!tnr_dmd)1155 return -EINVAL;1156 1157 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)1158 return -EINVAL;1159 1160 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)1161 return -EINVAL;1162 1163 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE)1164 return 0;1165 1166 ret = cxd2880_tnrdmd_dvbt2_mon_ofdm(tnr_dmd, &ofdm);1167 if (ret)1168 return ret;1169 1170 if (!ofdm.mixed)1171 return 0;1172 1173 ret = tnr_dmd->io->write_reg(tnr_dmd->io,1174 CXD2880_IO_TGT_DMD,1175 0x00, 0x1d);1176 if (ret)1177 return ret;1178 1179 return tnr_dmd->io->write_regs(tnr_dmd->io,1180 CXD2880_IO_TGT_DMD,1181 0x47, data, 12);1182}1183 1184int cxd2880_tnrdmd_dvbt2_check_l1post_valid(struct cxd2880_tnrdmd1185 *tnr_dmd,1186 u8 *l1_post_valid)1187{1188 int ret;1189 1190 u8 data;1191 1192 if (!tnr_dmd || !l1_post_valid)1193 return -EINVAL;1194 1195 if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)1196 return -EINVAL;1197 1198 if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP &&1199 tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)1200 return -EINVAL;1201 1202 ret = tnr_dmd->io->write_reg(tnr_dmd->io,1203 CXD2880_IO_TGT_DMD,1204 0x00, 0x0b);1205 if (ret)1206 return ret;1207 1208 ret = tnr_dmd->io->read_regs(tnr_dmd->io,1209 CXD2880_IO_TGT_DMD,1210 0x86, &data, 1);1211 if (ret)1212 return ret;1213 1214 *l1_post_valid = data & 0x01;1215 1216 return ret;1217}1218