cxd2880_tnrdmd_dvbt_mon.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * cxd2880_tnrdmd_dvbt_mon.c
  4. * Sony CXD2880 DVB-T2/T tuner + demodulator driver
  5. * DVB-T monitor functions
  6. *
  7. * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation
  8. */
  9. #include "cxd2880_tnrdmd_mon.h"
  10. #include "cxd2880_tnrdmd_dvbt.h"
  11. #include "cxd2880_tnrdmd_dvbt_mon.h"
  12. #include <media/dvb_math.h>
  13. static const int ref_dbm_1000[3][5] = {
  14. {-93000, -91000, -90000, -89000, -88000},
  15. {-87000, -85000, -84000, -83000, -82000},
  16. {-82000, -80000, -78000, -77000, -76000},
  17. };
  18. static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd);
  19. int cxd2880_tnrdmd_dvbt_mon_sync_stat(struct cxd2880_tnrdmd
  20. *tnr_dmd, u8 *sync_stat,
  21. u8 *ts_lock_stat,
  22. u8 *unlock_detected)
  23. {
  24. u8 rdata = 0x00;
  25. int ret;
  26. if (!tnr_dmd || !sync_stat || !ts_lock_stat || !unlock_detected)
  27. return -EINVAL;
  28. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  29. return -EINVAL;
  30. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  31. return -EINVAL;
  32. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  33. CXD2880_IO_TGT_DMD,
  34. 0x00, 0x0d);
  35. if (ret)
  36. return ret;
  37. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  38. CXD2880_IO_TGT_DMD,
  39. 0x10, &rdata, 1);
  40. if (ret)
  41. return ret;
  42. *unlock_detected = (rdata & 0x10) ? 1 : 0;
  43. *sync_stat = rdata & 0x07;
  44. *ts_lock_stat = (rdata & 0x20) ? 1 : 0;
  45. if (*sync_stat == 0x07)
  46. return -EAGAIN;
  47. return ret;
  48. }
  49. int cxd2880_tnrdmd_dvbt_mon_sync_stat_sub(struct cxd2880_tnrdmd
  50. *tnr_dmd, u8 *sync_stat,
  51. u8 *unlock_detected)
  52. {
  53. u8 ts_lock_stat = 0;
  54. if (!tnr_dmd || !sync_stat || !unlock_detected)
  55. return -EINVAL;
  56. if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
  57. return -EINVAL;
  58. return cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd->diver_sub,
  59. sync_stat,
  60. &ts_lock_stat,
  61. unlock_detected);
  62. }
  63. int cxd2880_tnrdmd_dvbt_mon_mode_guard(struct cxd2880_tnrdmd
  64. *tnr_dmd,
  65. enum cxd2880_dvbt_mode
  66. *mode,
  67. enum cxd2880_dvbt_guard
  68. *guard)
  69. {
  70. u8 rdata = 0x00;
  71. int ret;
  72. if (!tnr_dmd || !mode || !guard)
  73. return -EINVAL;
  74. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  75. return -EINVAL;
  76. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  77. return -EINVAL;
  78. ret = slvt_freeze_reg(tnr_dmd);
  79. if (ret)
  80. return ret;
  81. ret = is_tps_locked(tnr_dmd);
  82. if (ret) {
  83. slvt_unfreeze_reg(tnr_dmd);
  84. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
  85. ret =
  86. cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd->diver_sub,
  87. mode, guard);
  88. return ret;
  89. }
  90. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  91. CXD2880_IO_TGT_DMD,
  92. 0x00, 0x0d);
  93. if (ret) {
  94. slvt_unfreeze_reg(tnr_dmd);
  95. return ret;
  96. }
  97. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  98. CXD2880_IO_TGT_DMD,
  99. 0x1b, &rdata, 1);
  100. if (ret) {
  101. slvt_unfreeze_reg(tnr_dmd);
  102. return ret;
  103. }
  104. slvt_unfreeze_reg(tnr_dmd);
  105. *mode = (enum cxd2880_dvbt_mode)((rdata >> 2) & 0x03);
  106. *guard = (enum cxd2880_dvbt_guard)(rdata & 0x03);
  107. return ret;
  108. }
  109. int cxd2880_tnrdmd_dvbt_mon_carrier_offset(struct cxd2880_tnrdmd
  110. *tnr_dmd, int *offset)
  111. {
  112. u8 rdata[4];
  113. u32 ctl_val = 0;
  114. int ret;
  115. if (!tnr_dmd || !offset)
  116. return -EINVAL;
  117. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  118. return -EINVAL;
  119. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  120. return -EINVAL;
  121. ret = slvt_freeze_reg(tnr_dmd);
  122. if (ret)
  123. return ret;
  124. ret = is_tps_locked(tnr_dmd);
  125. if (ret) {
  126. slvt_unfreeze_reg(tnr_dmd);
  127. return ret;
  128. }
  129. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  130. CXD2880_IO_TGT_DMD,
  131. 0x00, 0x0d);
  132. if (ret) {
  133. slvt_unfreeze_reg(tnr_dmd);
  134. return ret;
  135. }
  136. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  137. CXD2880_IO_TGT_DMD,
  138. 0x1d, rdata, 4);
  139. if (ret) {
  140. slvt_unfreeze_reg(tnr_dmd);
  141. return ret;
  142. }
  143. slvt_unfreeze_reg(tnr_dmd);
  144. ctl_val =
  145. ((rdata[0] & 0x1f) << 24) | (rdata[1] << 16) | (rdata[2] << 8) |
  146. (rdata[3]);
  147. *offset = cxd2880_convert2s_complement(ctl_val, 29);
  148. *offset = -1 * ((*offset) * tnr_dmd->bandwidth / 235);
  149. return ret;
  150. }
  151. int cxd2880_tnrdmd_dvbt_mon_carrier_offset_sub(struct
  152. cxd2880_tnrdmd
  153. *tnr_dmd,
  154. int *offset)
  155. {
  156. if (!tnr_dmd || !offset)
  157. return -EINVAL;
  158. if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
  159. return -EINVAL;
  160. return cxd2880_tnrdmd_dvbt_mon_carrier_offset(tnr_dmd->diver_sub,
  161. offset);
  162. }
  163. int cxd2880_tnrdmd_dvbt_mon_tps_info(struct cxd2880_tnrdmd
  164. *tnr_dmd,
  165. struct cxd2880_dvbt_tpsinfo
  166. *info)
  167. {
  168. u8 rdata[7];
  169. u8 cell_id_ok = 0;
  170. int ret;
  171. if (!tnr_dmd || !info)
  172. return -EINVAL;
  173. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  174. return -EINVAL;
  175. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  176. return -EINVAL;
  177. ret = slvt_freeze_reg(tnr_dmd);
  178. if (ret)
  179. return ret;
  180. ret = is_tps_locked(tnr_dmd);
  181. if (ret) {
  182. slvt_unfreeze_reg(tnr_dmd);
  183. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
  184. ret =
  185. cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd->diver_sub,
  186. info);
  187. return ret;
  188. }
  189. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  190. CXD2880_IO_TGT_DMD,
  191. 0x00, 0x0d);
  192. if (ret) {
  193. slvt_unfreeze_reg(tnr_dmd);
  194. return ret;
  195. }
  196. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  197. CXD2880_IO_TGT_DMD,
  198. 0x29, rdata, 7);
  199. if (ret) {
  200. slvt_unfreeze_reg(tnr_dmd);
  201. return ret;
  202. }
  203. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  204. CXD2880_IO_TGT_DMD,
  205. 0x00, 0x11);
  206. if (ret) {
  207. slvt_unfreeze_reg(tnr_dmd);
  208. return ret;
  209. }
  210. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  211. CXD2880_IO_TGT_DMD,
  212. 0xd5, &cell_id_ok, 1);
  213. if (ret) {
  214. slvt_unfreeze_reg(tnr_dmd);
  215. return ret;
  216. }
  217. slvt_unfreeze_reg(tnr_dmd);
  218. info->constellation =
  219. (enum cxd2880_dvbt_constellation)((rdata[0] >> 6) & 0x03);
  220. info->hierarchy = (enum cxd2880_dvbt_hierarchy)((rdata[0] >> 3) & 0x07);
  221. info->rate_hp = (enum cxd2880_dvbt_coderate)(rdata[0] & 0x07);
  222. info->rate_lp = (enum cxd2880_dvbt_coderate)((rdata[1] >> 5) & 0x07);
  223. info->guard = (enum cxd2880_dvbt_guard)((rdata[1] >> 3) & 0x03);
  224. info->mode = (enum cxd2880_dvbt_mode)((rdata[1] >> 1) & 0x03);
  225. info->fnum = (rdata[2] >> 6) & 0x03;
  226. info->length_indicator = rdata[2] & 0x3f;
  227. info->cell_id = (rdata[3] << 8) | rdata[4];
  228. info->reserved_even = rdata[5] & 0x3f;
  229. info->reserved_odd = rdata[6] & 0x3f;
  230. info->cell_id_ok = cell_id_ok & 0x01;
  231. return ret;
  232. }
  233. int cxd2880_tnrdmd_dvbt_mon_packet_error_number(struct
  234. cxd2880_tnrdmd
  235. *tnr_dmd,
  236. u32 *pen)
  237. {
  238. u8 rdata[3];
  239. int ret;
  240. if (!tnr_dmd || !pen)
  241. return -EINVAL;
  242. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
  243. return -EINVAL;
  244. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  245. return -EINVAL;
  246. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  247. return -EINVAL;
  248. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  249. CXD2880_IO_TGT_DMD,
  250. 0x00, 0x0d);
  251. if (ret)
  252. return ret;
  253. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  254. CXD2880_IO_TGT_DMD,
  255. 0x26, rdata, 3);
  256. if (ret)
  257. return ret;
  258. if (!(rdata[0] & 0x01))
  259. return -EAGAIN;
  260. *pen = (rdata[1] << 8) | rdata[2];
  261. return ret;
  262. }
  263. int cxd2880_tnrdmd_dvbt_mon_spectrum_sense(struct cxd2880_tnrdmd
  264. *tnr_dmd,
  265. enum
  266. cxd2880_tnrdmd_spectrum_sense
  267. *sense)
  268. {
  269. u8 data = 0;
  270. int ret;
  271. if (!tnr_dmd || !sense)
  272. return -EINVAL;
  273. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  274. return -EINVAL;
  275. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  276. return -EINVAL;
  277. ret = slvt_freeze_reg(tnr_dmd);
  278. if (ret)
  279. return ret;
  280. ret = is_tps_locked(tnr_dmd);
  281. if (ret) {
  282. slvt_unfreeze_reg(tnr_dmd);
  283. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_MAIN)
  284. ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd->diver_sub,
  285. sense);
  286. return ret;
  287. }
  288. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  289. CXD2880_IO_TGT_DMD,
  290. 0x00, 0x0d);
  291. if (ret) {
  292. slvt_unfreeze_reg(tnr_dmd);
  293. return ret;
  294. }
  295. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  296. CXD2880_IO_TGT_DMD,
  297. 0x1c, &data, sizeof(data));
  298. if (ret) {
  299. slvt_unfreeze_reg(tnr_dmd);
  300. return ret;
  301. }
  302. slvt_unfreeze_reg(tnr_dmd);
  303. *sense =
  304. (data & 0x01) ? CXD2880_TNRDMD_SPECTRUM_INV :
  305. CXD2880_TNRDMD_SPECTRUM_NORMAL;
  306. return ret;
  307. }
  308. static int dvbt_read_snr_reg(struct cxd2880_tnrdmd *tnr_dmd,
  309. u16 *reg_value)
  310. {
  311. u8 rdata[2];
  312. int ret;
  313. if (!tnr_dmd || !reg_value)
  314. return -EINVAL;
  315. ret = slvt_freeze_reg(tnr_dmd);
  316. if (ret)
  317. return ret;
  318. ret = is_tps_locked(tnr_dmd);
  319. if (ret) {
  320. slvt_unfreeze_reg(tnr_dmd);
  321. return ret;
  322. }
  323. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  324. CXD2880_IO_TGT_DMD,
  325. 0x00, 0x0d);
  326. if (ret) {
  327. slvt_unfreeze_reg(tnr_dmd);
  328. return ret;
  329. }
  330. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  331. CXD2880_IO_TGT_DMD,
  332. 0x13, rdata, 2);
  333. if (ret) {
  334. slvt_unfreeze_reg(tnr_dmd);
  335. return ret;
  336. }
  337. slvt_unfreeze_reg(tnr_dmd);
  338. *reg_value = (rdata[0] << 8) | rdata[1];
  339. return ret;
  340. }
  341. static int dvbt_calc_snr(struct cxd2880_tnrdmd *tnr_dmd,
  342. u32 reg_value, int *snr)
  343. {
  344. if (!tnr_dmd || !snr)
  345. return -EINVAL;
  346. if (reg_value == 0)
  347. return -EAGAIN;
  348. if (reg_value > 4996)
  349. reg_value = 4996;
  350. *snr = intlog10(reg_value) - intlog10(5350 - reg_value);
  351. *snr = (*snr + 839) / 1678 + 28500;
  352. return 0;
  353. }
  354. int cxd2880_tnrdmd_dvbt_mon_snr(struct cxd2880_tnrdmd *tnr_dmd,
  355. int *snr)
  356. {
  357. u16 reg_value = 0;
  358. int ret;
  359. if (!tnr_dmd || !snr)
  360. return -EINVAL;
  361. *snr = -1000 * 1000;
  362. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
  363. return -EINVAL;
  364. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  365. return -EINVAL;
  366. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  367. return -EINVAL;
  368. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SINGLE) {
  369. ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
  370. if (ret)
  371. return ret;
  372. ret = dvbt_calc_snr(tnr_dmd, reg_value, snr);
  373. } else {
  374. int snr_main = 0;
  375. int snr_sub = 0;
  376. ret =
  377. cxd2880_tnrdmd_dvbt_mon_snr_diver(tnr_dmd, snr, &snr_main,
  378. &snr_sub);
  379. }
  380. return ret;
  381. }
  382. int cxd2880_tnrdmd_dvbt_mon_snr_diver(struct cxd2880_tnrdmd
  383. *tnr_dmd, int *snr,
  384. int *snr_main, int *snr_sub)
  385. {
  386. u16 reg_value = 0;
  387. u32 reg_value_sum = 0;
  388. int ret;
  389. if (!tnr_dmd || !snr || !snr_main || !snr_sub)
  390. return -EINVAL;
  391. *snr = -1000 * 1000;
  392. *snr_main = -1000 * 1000;
  393. *snr_sub = -1000 * 1000;
  394. if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
  395. return -EINVAL;
  396. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  397. return -EINVAL;
  398. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  399. return -EINVAL;
  400. ret = dvbt_read_snr_reg(tnr_dmd, &reg_value);
  401. if (!ret) {
  402. ret = dvbt_calc_snr(tnr_dmd, reg_value, snr_main);
  403. if (ret)
  404. reg_value = 0;
  405. } else if (ret == -EAGAIN) {
  406. reg_value = 0;
  407. } else {
  408. return ret;
  409. }
  410. reg_value_sum += reg_value;
  411. ret = dvbt_read_snr_reg(tnr_dmd->diver_sub, &reg_value);
  412. if (!ret) {
  413. ret = dvbt_calc_snr(tnr_dmd->diver_sub, reg_value, snr_sub);
  414. if (ret)
  415. reg_value = 0;
  416. } else if (ret == -EAGAIN) {
  417. reg_value = 0;
  418. } else {
  419. return ret;
  420. }
  421. reg_value_sum += reg_value;
  422. return dvbt_calc_snr(tnr_dmd, reg_value_sum, snr);
  423. }
  424. int cxd2880_tnrdmd_dvbt_mon_sampling_offset(struct cxd2880_tnrdmd
  425. *tnr_dmd, int *ppm)
  426. {
  427. u8 ctl_val_reg[5];
  428. u8 nominal_rate_reg[5];
  429. u32 trl_ctl_val = 0;
  430. u32 trcg_nominal_rate = 0;
  431. int num;
  432. int den;
  433. s8 diff_upper = 0;
  434. int ret;
  435. if (!tnr_dmd || !ppm)
  436. return -EINVAL;
  437. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  438. return -EINVAL;
  439. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  440. return -EINVAL;
  441. ret = slvt_freeze_reg(tnr_dmd);
  442. if (ret)
  443. return ret;
  444. ret = is_tps_locked(tnr_dmd);
  445. if (ret) {
  446. slvt_unfreeze_reg(tnr_dmd);
  447. return ret;
  448. }
  449. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  450. CXD2880_IO_TGT_DMD,
  451. 0x00, 0x0d);
  452. if (ret) {
  453. slvt_unfreeze_reg(tnr_dmd);
  454. return ret;
  455. }
  456. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  457. CXD2880_IO_TGT_DMD,
  458. 0x21, ctl_val_reg,
  459. sizeof(ctl_val_reg));
  460. if (ret) {
  461. slvt_unfreeze_reg(tnr_dmd);
  462. return ret;
  463. }
  464. ret = tnr_dmd->io->write_reg(tnr_dmd->io,
  465. CXD2880_IO_TGT_DMD,
  466. 0x00, 0x04);
  467. if (ret) {
  468. slvt_unfreeze_reg(tnr_dmd);
  469. return ret;
  470. }
  471. ret = tnr_dmd->io->read_regs(tnr_dmd->io,
  472. CXD2880_IO_TGT_DMD,
  473. 0x60, nominal_rate_reg,
  474. sizeof(nominal_rate_reg));
  475. if (ret) {
  476. slvt_unfreeze_reg(tnr_dmd);
  477. return ret;
  478. }
  479. slvt_unfreeze_reg(tnr_dmd);
  480. diff_upper =
  481. (ctl_val_reg[0] & 0x7f) - (nominal_rate_reg[0] & 0x7f);
  482. if (diff_upper < -1 || diff_upper > 1)
  483. return -EAGAIN;
  484. trl_ctl_val = ctl_val_reg[1] << 24;
  485. trl_ctl_val |= ctl_val_reg[2] << 16;
  486. trl_ctl_val |= ctl_val_reg[3] << 8;
  487. trl_ctl_val |= ctl_val_reg[4];
  488. trcg_nominal_rate = nominal_rate_reg[1] << 24;
  489. trcg_nominal_rate |= nominal_rate_reg[2] << 16;
  490. trcg_nominal_rate |= nominal_rate_reg[3] << 8;
  491. trcg_nominal_rate |= nominal_rate_reg[4];
  492. trl_ctl_val >>= 1;
  493. trcg_nominal_rate >>= 1;
  494. if (diff_upper == 1)
  495. num =
  496. (int)((trl_ctl_val + 0x80000000u) -
  497. trcg_nominal_rate);
  498. else if (diff_upper == -1)
  499. num =
  500. -(int)((trcg_nominal_rate + 0x80000000u) -
  501. trl_ctl_val);
  502. else
  503. num = (int)(trl_ctl_val - trcg_nominal_rate);
  504. den = (nominal_rate_reg[0] & 0x7f) << 24;
  505. den |= nominal_rate_reg[1] << 16;
  506. den |= nominal_rate_reg[2] << 8;
  507. den |= nominal_rate_reg[3];
  508. den = (den + (390625 / 2)) / 390625;
  509. den >>= 1;
  510. if (num >= 0)
  511. *ppm = (num + (den / 2)) / den;
  512. else
  513. *ppm = (num - (den / 2)) / den;
  514. return ret;
  515. }
  516. int cxd2880_tnrdmd_dvbt_mon_sampling_offset_sub(struct
  517. cxd2880_tnrdmd
  518. *tnr_dmd, int *ppm)
  519. {
  520. if (!tnr_dmd || !ppm)
  521. return -EINVAL;
  522. if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
  523. return -EINVAL;
  524. return cxd2880_tnrdmd_dvbt_mon_sampling_offset(tnr_dmd->diver_sub, ppm);
  525. }
  526. static int dvbt_calc_ssi(struct cxd2880_tnrdmd *tnr_dmd,
  527. int rf_lvl, u8 *ssi)
  528. {
  529. struct cxd2880_dvbt_tpsinfo tps;
  530. int prel;
  531. int temp_ssi = 0;
  532. int ret;
  533. if (!tnr_dmd || !ssi)
  534. return -EINVAL;
  535. ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd, &tps);
  536. if (ret)
  537. return ret;
  538. if (tps.constellation >= CXD2880_DVBT_CONSTELLATION_RESERVED_3 ||
  539. tps.rate_hp >= CXD2880_DVBT_CODERATE_RESERVED_5)
  540. return -EINVAL;
  541. prel = rf_lvl - ref_dbm_1000[tps.constellation][tps.rate_hp];
  542. if (prel < -15000)
  543. temp_ssi = 0;
  544. else if (prel < 0)
  545. temp_ssi = ((2 * (prel + 15000)) + 1500) / 3000;
  546. else if (prel < 20000)
  547. temp_ssi = (((4 * prel) + 500) / 1000) + 10;
  548. else if (prel < 35000)
  549. temp_ssi = (((2 * (prel - 20000)) + 1500) / 3000) + 90;
  550. else
  551. temp_ssi = 100;
  552. *ssi = (temp_ssi > 100) ? 100 : (u8)temp_ssi;
  553. return ret;
  554. }
  555. int cxd2880_tnrdmd_dvbt_mon_ssi(struct cxd2880_tnrdmd *tnr_dmd,
  556. u8 *ssi)
  557. {
  558. int rf_lvl = 0;
  559. int ret;
  560. if (!tnr_dmd || !ssi)
  561. return -EINVAL;
  562. if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB)
  563. return -EINVAL;
  564. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  565. return -EINVAL;
  566. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  567. return -EINVAL;
  568. ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd, &rf_lvl);
  569. if (ret)
  570. return ret;
  571. return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
  572. }
  573. int cxd2880_tnrdmd_dvbt_mon_ssi_sub(struct cxd2880_tnrdmd *tnr_dmd,
  574. u8 *ssi)
  575. {
  576. int rf_lvl = 0;
  577. int ret;
  578. if (!tnr_dmd || !ssi)
  579. return -EINVAL;
  580. if (tnr_dmd->diver_mode != CXD2880_TNRDMD_DIVERMODE_MAIN)
  581. return -EINVAL;
  582. if (tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE)
  583. return -EINVAL;
  584. if (tnr_dmd->sys != CXD2880_DTV_SYS_DVBT)
  585. return -EINVAL;
  586. ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd->diver_sub, &rf_lvl);
  587. if (ret)
  588. return ret;
  589. return dvbt_calc_ssi(tnr_dmd, rf_lvl, ssi);
  590. }
  591. static int is_tps_locked(struct cxd2880_tnrdmd *tnr_dmd)
  592. {
  593. u8 sync = 0;
  594. u8 tslock = 0;
  595. u8 early_unlock = 0;
  596. int ret;
  597. if (!tnr_dmd)
  598. return -EINVAL;
  599. ret =
  600. cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd, &sync, &tslock,
  601. &early_unlock);
  602. if (ret)
  603. return ret;
  604. if (sync != 6)
  605. return -EAGAIN;
  606. return 0;
  607. }