as102_fe.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Abilis Systems Single DVB-T Receiver
  4. * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
  5. * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
  6. */
  7. #include <media/dvb_frontend.h>
  8. #include "as102_fe.h"
  9. struct as102_state {
  10. struct dvb_frontend frontend;
  11. struct as10x_demod_stats demod_stats;
  12. const struct as102_fe_ops *ops;
  13. void *priv;
  14. uint8_t elna_cfg;
  15. /* signal strength */
  16. uint16_t signal_strength;
  17. /* bit error rate */
  18. uint32_t ber;
  19. };
  20. static uint8_t as102_fe_get_code_rate(enum fe_code_rate arg)
  21. {
  22. uint8_t c;
  23. switch (arg) {
  24. case FEC_1_2:
  25. c = CODE_RATE_1_2;
  26. break;
  27. case FEC_2_3:
  28. c = CODE_RATE_2_3;
  29. break;
  30. case FEC_3_4:
  31. c = CODE_RATE_3_4;
  32. break;
  33. case FEC_5_6:
  34. c = CODE_RATE_5_6;
  35. break;
  36. case FEC_7_8:
  37. c = CODE_RATE_7_8;
  38. break;
  39. default:
  40. c = CODE_RATE_UNKNOWN;
  41. break;
  42. }
  43. return c;
  44. }
  45. static int as102_fe_set_frontend(struct dvb_frontend *fe)
  46. {
  47. struct as102_state *state = fe->demodulator_priv;
  48. struct dtv_frontend_properties *c = &fe->dtv_property_cache;
  49. struct as10x_tune_args tune_args = { 0 };
  50. /* set frequency */
  51. tune_args.freq = c->frequency / 1000;
  52. /* fix interleaving_mode */
  53. tune_args.interleaving_mode = INTLV_NATIVE;
  54. switch (c->bandwidth_hz) {
  55. case 8000000:
  56. tune_args.bandwidth = BW_8_MHZ;
  57. break;
  58. case 7000000:
  59. tune_args.bandwidth = BW_7_MHZ;
  60. break;
  61. case 6000000:
  62. tune_args.bandwidth = BW_6_MHZ;
  63. break;
  64. default:
  65. tune_args.bandwidth = BW_8_MHZ;
  66. }
  67. switch (c->guard_interval) {
  68. case GUARD_INTERVAL_1_32:
  69. tune_args.guard_interval = GUARD_INT_1_32;
  70. break;
  71. case GUARD_INTERVAL_1_16:
  72. tune_args.guard_interval = GUARD_INT_1_16;
  73. break;
  74. case GUARD_INTERVAL_1_8:
  75. tune_args.guard_interval = GUARD_INT_1_8;
  76. break;
  77. case GUARD_INTERVAL_1_4:
  78. tune_args.guard_interval = GUARD_INT_1_4;
  79. break;
  80. case GUARD_INTERVAL_AUTO:
  81. default:
  82. tune_args.guard_interval = GUARD_UNKNOWN;
  83. break;
  84. }
  85. switch (c->modulation) {
  86. case QPSK:
  87. tune_args.modulation = CONST_QPSK;
  88. break;
  89. case QAM_16:
  90. tune_args.modulation = CONST_QAM16;
  91. break;
  92. case QAM_64:
  93. tune_args.modulation = CONST_QAM64;
  94. break;
  95. default:
  96. tune_args.modulation = CONST_UNKNOWN;
  97. break;
  98. }
  99. switch (c->transmission_mode) {
  100. case TRANSMISSION_MODE_2K:
  101. tune_args.transmission_mode = TRANS_MODE_2K;
  102. break;
  103. case TRANSMISSION_MODE_8K:
  104. tune_args.transmission_mode = TRANS_MODE_8K;
  105. break;
  106. default:
  107. tune_args.transmission_mode = TRANS_MODE_UNKNOWN;
  108. }
  109. switch (c->hierarchy) {
  110. case HIERARCHY_NONE:
  111. tune_args.hierarchy = HIER_NONE;
  112. break;
  113. case HIERARCHY_1:
  114. tune_args.hierarchy = HIER_ALPHA_1;
  115. break;
  116. case HIERARCHY_2:
  117. tune_args.hierarchy = HIER_ALPHA_2;
  118. break;
  119. case HIERARCHY_4:
  120. tune_args.hierarchy = HIER_ALPHA_4;
  121. break;
  122. case HIERARCHY_AUTO:
  123. tune_args.hierarchy = HIER_UNKNOWN;
  124. break;
  125. }
  126. pr_debug("as102: tuner parameters: freq: %d bw: 0x%02x gi: 0x%02x\n",
  127. c->frequency,
  128. tune_args.bandwidth,
  129. tune_args.guard_interval);
  130. /*
  131. * Detect a hierarchy selection
  132. * if HP/LP are both set to FEC_NONE, HP will be selected.
  133. */
  134. if ((tune_args.hierarchy != HIER_NONE) &&
  135. ((c->code_rate_LP == FEC_NONE) ||
  136. (c->code_rate_HP == FEC_NONE))) {
  137. if (c->code_rate_LP == FEC_NONE) {
  138. tune_args.hier_select = HIER_HIGH_PRIORITY;
  139. tune_args.code_rate =
  140. as102_fe_get_code_rate(c->code_rate_HP);
  141. }
  142. if (c->code_rate_HP == FEC_NONE) {
  143. tune_args.hier_select = HIER_LOW_PRIORITY;
  144. tune_args.code_rate =
  145. as102_fe_get_code_rate(c->code_rate_LP);
  146. }
  147. pr_debug("as102: \thierarchy: 0x%02x selected: %s code_rate_%s: 0x%02x\n",
  148. tune_args.hierarchy,
  149. tune_args.hier_select == HIER_HIGH_PRIORITY ?
  150. "HP" : "LP",
  151. tune_args.hier_select == HIER_HIGH_PRIORITY ?
  152. "HP" : "LP",
  153. tune_args.code_rate);
  154. } else {
  155. tune_args.code_rate =
  156. as102_fe_get_code_rate(c->code_rate_HP);
  157. }
  158. /* Set frontend arguments */
  159. return state->ops->set_tune(state->priv, &tune_args);
  160. }
  161. static int as102_fe_get_frontend(struct dvb_frontend *fe,
  162. struct dtv_frontend_properties *c)
  163. {
  164. struct as102_state *state = fe->demodulator_priv;
  165. int ret = 0;
  166. struct as10x_tps tps = { 0 };
  167. /* send abilis command: GET_TPS */
  168. ret = state->ops->get_tps(state->priv, &tps);
  169. if (ret < 0)
  170. return ret;
  171. /* extract constellation */
  172. switch (tps.modulation) {
  173. case CONST_QPSK:
  174. c->modulation = QPSK;
  175. break;
  176. case CONST_QAM16:
  177. c->modulation = QAM_16;
  178. break;
  179. case CONST_QAM64:
  180. c->modulation = QAM_64;
  181. break;
  182. }
  183. /* extract hierarchy */
  184. switch (tps.hierarchy) {
  185. case HIER_NONE:
  186. c->hierarchy = HIERARCHY_NONE;
  187. break;
  188. case HIER_ALPHA_1:
  189. c->hierarchy = HIERARCHY_1;
  190. break;
  191. case HIER_ALPHA_2:
  192. c->hierarchy = HIERARCHY_2;
  193. break;
  194. case HIER_ALPHA_4:
  195. c->hierarchy = HIERARCHY_4;
  196. break;
  197. }
  198. /* extract code rate HP */
  199. switch (tps.code_rate_HP) {
  200. case CODE_RATE_1_2:
  201. c->code_rate_HP = FEC_1_2;
  202. break;
  203. case CODE_RATE_2_3:
  204. c->code_rate_HP = FEC_2_3;
  205. break;
  206. case CODE_RATE_3_4:
  207. c->code_rate_HP = FEC_3_4;
  208. break;
  209. case CODE_RATE_5_6:
  210. c->code_rate_HP = FEC_5_6;
  211. break;
  212. case CODE_RATE_7_8:
  213. c->code_rate_HP = FEC_7_8;
  214. break;
  215. }
  216. /* extract code rate LP */
  217. switch (tps.code_rate_LP) {
  218. case CODE_RATE_1_2:
  219. c->code_rate_LP = FEC_1_2;
  220. break;
  221. case CODE_RATE_2_3:
  222. c->code_rate_LP = FEC_2_3;
  223. break;
  224. case CODE_RATE_3_4:
  225. c->code_rate_LP = FEC_3_4;
  226. break;
  227. case CODE_RATE_5_6:
  228. c->code_rate_LP = FEC_5_6;
  229. break;
  230. case CODE_RATE_7_8:
  231. c->code_rate_LP = FEC_7_8;
  232. break;
  233. }
  234. /* extract guard interval */
  235. switch (tps.guard_interval) {
  236. case GUARD_INT_1_32:
  237. c->guard_interval = GUARD_INTERVAL_1_32;
  238. break;
  239. case GUARD_INT_1_16:
  240. c->guard_interval = GUARD_INTERVAL_1_16;
  241. break;
  242. case GUARD_INT_1_8:
  243. c->guard_interval = GUARD_INTERVAL_1_8;
  244. break;
  245. case GUARD_INT_1_4:
  246. c->guard_interval = GUARD_INTERVAL_1_4;
  247. break;
  248. }
  249. /* extract transmission mode */
  250. switch (tps.transmission_mode) {
  251. case TRANS_MODE_2K:
  252. c->transmission_mode = TRANSMISSION_MODE_2K;
  253. break;
  254. case TRANS_MODE_8K:
  255. c->transmission_mode = TRANSMISSION_MODE_8K;
  256. break;
  257. }
  258. return 0;
  259. }
  260. static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
  261. struct dvb_frontend_tune_settings *settings) {
  262. settings->min_delay_ms = 1000;
  263. return 0;
  264. }
  265. static int as102_fe_read_status(struct dvb_frontend *fe, enum fe_status *status)
  266. {
  267. int ret = 0;
  268. struct as102_state *state = fe->demodulator_priv;
  269. struct as10x_tune_status tstate = { 0 };
  270. /* send abilis command: GET_TUNE_STATUS */
  271. ret = state->ops->get_status(state->priv, &tstate);
  272. if (ret < 0)
  273. return ret;
  274. state->signal_strength = tstate.signal_strength;
  275. state->ber = tstate.BER;
  276. switch (tstate.tune_state) {
  277. case TUNE_STATUS_SIGNAL_DVB_OK:
  278. *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
  279. break;
  280. case TUNE_STATUS_STREAM_DETECTED:
  281. *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
  282. FE_HAS_VITERBI;
  283. break;
  284. case TUNE_STATUS_STREAM_TUNED:
  285. *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC |
  286. FE_HAS_LOCK | FE_HAS_VITERBI;
  287. break;
  288. default:
  289. *status = TUNE_STATUS_NOT_TUNED;
  290. }
  291. pr_debug("as102: tuner status: 0x%02x, strength %d, per: %d, ber: %d\n",
  292. tstate.tune_state, tstate.signal_strength,
  293. tstate.PER, tstate.BER);
  294. if (!(*status & FE_HAS_LOCK)) {
  295. memset(&state->demod_stats, 0, sizeof(state->demod_stats));
  296. return 0;
  297. }
  298. ret = state->ops->get_stats(state->priv, &state->demod_stats);
  299. if (ret < 0)
  300. memset(&state->demod_stats, 0, sizeof(state->demod_stats));
  301. return ret;
  302. }
  303. /*
  304. * Note:
  305. * - in AS102 SNR=MER
  306. * - the SNR will be returned in linear terms, i.e. not in dB
  307. * - the accuracy equals ±2dB for a SNR range from 4dB to 30dB
  308. * - the accuracy is >2dB for SNR values outside this range
  309. */
  310. static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
  311. {
  312. struct as102_state *state = fe->demodulator_priv;
  313. *snr = state->demod_stats.mer;
  314. return 0;
  315. }
  316. static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
  317. {
  318. struct as102_state *state = fe->demodulator_priv;
  319. *ber = state->ber;
  320. return 0;
  321. }
  322. static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
  323. u16 *strength)
  324. {
  325. struct as102_state *state = fe->demodulator_priv;
  326. *strength = (((0xffff * 400) * state->signal_strength + 41000) * 2);
  327. return 0;
  328. }
  329. static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
  330. {
  331. struct as102_state *state = fe->demodulator_priv;
  332. if (state->demod_stats.has_started)
  333. *ucblocks = state->demod_stats.bad_frame_count;
  334. else
  335. *ucblocks = 0;
  336. return 0;
  337. }
  338. static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
  339. {
  340. struct as102_state *state = fe->demodulator_priv;
  341. return state->ops->stream_ctrl(state->priv, acquire,
  342. state->elna_cfg);
  343. }
  344. static void as102_fe_release(struct dvb_frontend *fe)
  345. {
  346. struct as102_state *state = fe->demodulator_priv;
  347. kfree(state);
  348. }
  349. static const struct dvb_frontend_ops as102_fe_ops = {
  350. .delsys = { SYS_DVBT },
  351. .info = {
  352. .name = "Abilis AS102 DVB-T",
  353. .frequency_min_hz = 174 * MHz,
  354. .frequency_max_hz = 862 * MHz,
  355. .frequency_stepsize_hz = 166667,
  356. .caps = FE_CAN_INVERSION_AUTO
  357. | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4
  358. | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO
  359. | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QPSK
  360. | FE_CAN_QAM_AUTO
  361. | FE_CAN_TRANSMISSION_MODE_AUTO
  362. | FE_CAN_GUARD_INTERVAL_AUTO
  363. | FE_CAN_HIERARCHY_AUTO
  364. | FE_CAN_RECOVER
  365. | FE_CAN_MUTE_TS
  366. },
  367. .set_frontend = as102_fe_set_frontend,
  368. .get_frontend = as102_fe_get_frontend,
  369. .get_tune_settings = as102_fe_get_tune_settings,
  370. .read_status = as102_fe_read_status,
  371. .read_snr = as102_fe_read_snr,
  372. .read_ber = as102_fe_read_ber,
  373. .read_signal_strength = as102_fe_read_signal_strength,
  374. .read_ucblocks = as102_fe_read_ucblocks,
  375. .ts_bus_ctrl = as102_fe_ts_bus_ctrl,
  376. .release = as102_fe_release,
  377. };
  378. struct dvb_frontend *as102_attach(const char *name,
  379. const struct as102_fe_ops *ops,
  380. void *priv,
  381. uint8_t elna_cfg)
  382. {
  383. struct as102_state *state;
  384. struct dvb_frontend *fe;
  385. state = kzalloc(sizeof(*state), GFP_KERNEL);
  386. if (!state)
  387. return NULL;
  388. fe = &state->frontend;
  389. fe->demodulator_priv = state;
  390. state->ops = ops;
  391. state->priv = priv;
  392. state->elna_cfg = elna_cfg;
  393. /* init frontend callback ops */
  394. memcpy(&fe->ops, &as102_fe_ops, sizeof(struct dvb_frontend_ops));
  395. strscpy(fe->ops.info.name, name, sizeof(fe->ops.info.name));
  396. return fe;
  397. }
  398. EXPORT_SYMBOL_GPL(as102_attach);
  399. MODULE_DESCRIPTION("as102-fe");
  400. MODULE_LICENSE("GPL");
  401. MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");