as102_fe.c 11 KB

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