1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * cxd2880_top.c |
4 | * Sony CXD2880 DVB-T2/T tuner + demodulator driver |
5 | * |
6 | * Copyright (C) 2016, 2017, 2018 Sony Semiconductor Solutions Corporation |
7 | */ |
8 | |
9 | #define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__ |
10 | |
11 | #include <linux/spi/spi.h> |
12 | |
13 | #include <media/dvb_frontend.h> |
14 | #include <linux/int_log.h> |
15 | |
16 | #include "cxd2880.h" |
17 | #include "cxd2880_tnrdmd_mon.h" |
18 | #include "cxd2880_tnrdmd_dvbt2_mon.h" |
19 | #include "cxd2880_tnrdmd_dvbt_mon.h" |
20 | #include "cxd2880_integ.h" |
21 | #include "cxd2880_tnrdmd_dvbt2.h" |
22 | #include "cxd2880_tnrdmd_dvbt.h" |
23 | #include "cxd2880_devio_spi.h" |
24 | #include "cxd2880_spi_device.h" |
25 | #include "cxd2880_tnrdmd_driver_version.h" |
26 | |
27 | struct cxd2880_priv { |
28 | struct cxd2880_tnrdmd tnrdmd; |
29 | struct spi_device *spi; |
30 | struct cxd2880_io regio; |
31 | struct cxd2880_spi_device spi_device; |
32 | struct cxd2880_spi cxd2880_spi; |
33 | struct cxd2880_dvbt_tune_param dvbt_tune_param; |
34 | struct cxd2880_dvbt2_tune_param dvbt2_tune_param; |
35 | struct mutex *spi_mutex; /* For SPI access exclusive control */ |
36 | unsigned long pre_ber_update; |
37 | unsigned long pre_ber_interval; |
38 | unsigned long post_ber_update; |
39 | unsigned long post_ber_interval; |
40 | unsigned long ucblock_update; |
41 | unsigned long ucblock_interval; |
42 | enum fe_status s; |
43 | }; |
44 | |
45 | static int cxd2880_pre_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, |
46 | u32 *pre_bit_err, u32 *pre_bit_count) |
47 | { |
48 | u8 rdata[2]; |
49 | int ret; |
50 | |
51 | if (!tnrdmd || !pre_bit_err || !pre_bit_count) |
52 | return -EINVAL; |
53 | |
54 | if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
55 | return -EINVAL; |
56 | |
57 | if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
58 | return -EINVAL; |
59 | |
60 | if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) |
61 | return -EINVAL; |
62 | |
63 | ret = slvt_freeze_reg(tnr_dmd: tnrdmd); |
64 | if (ret) |
65 | return ret; |
66 | |
67 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
68 | CXD2880_IO_TGT_DMD, |
69 | 0x00, 0x10); |
70 | if (ret) { |
71 | slvt_unfreeze_reg(tnrdmd); |
72 | return ret; |
73 | } |
74 | |
75 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
76 | CXD2880_IO_TGT_DMD, |
77 | 0x39, rdata, 1); |
78 | if (ret) { |
79 | slvt_unfreeze_reg(tnrdmd); |
80 | return ret; |
81 | } |
82 | |
83 | if ((rdata[0] & 0x01) == 0) { |
84 | slvt_unfreeze_reg(tnrdmd); |
85 | return -EAGAIN; |
86 | } |
87 | |
88 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
89 | CXD2880_IO_TGT_DMD, |
90 | 0x22, rdata, 2); |
91 | if (ret) { |
92 | slvt_unfreeze_reg(tnrdmd); |
93 | return ret; |
94 | } |
95 | |
96 | *pre_bit_err = (rdata[0] << 8) | rdata[1]; |
97 | |
98 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
99 | CXD2880_IO_TGT_DMD, |
100 | 0x6f, rdata, 1); |
101 | if (ret) { |
102 | slvt_unfreeze_reg(tnrdmd); |
103 | return ret; |
104 | } |
105 | |
106 | slvt_unfreeze_reg(tnrdmd); |
107 | |
108 | *pre_bit_count = ((rdata[0] & 0x07) == 0) ? |
109 | 256 : (0x1000 << (rdata[0] & 0x07)); |
110 | |
111 | return 0; |
112 | } |
113 | |
114 | static int cxd2880_pre_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, |
115 | u32 *pre_bit_err, |
116 | u32 *pre_bit_count) |
117 | { |
118 | u32 period_exp = 0; |
119 | u32 n_ldpc = 0; |
120 | u8 data[5]; |
121 | int ret; |
122 | |
123 | if (!tnrdmd || !pre_bit_err || !pre_bit_count) |
124 | return -EINVAL; |
125 | |
126 | if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
127 | return -EINVAL; |
128 | |
129 | if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
130 | return -EINVAL; |
131 | |
132 | if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) |
133 | return -EINVAL; |
134 | |
135 | ret = slvt_freeze_reg(tnr_dmd: tnrdmd); |
136 | if (ret) |
137 | return ret; |
138 | |
139 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
140 | CXD2880_IO_TGT_DMD, |
141 | 0x00, 0x0b); |
142 | if (ret) { |
143 | slvt_unfreeze_reg(tnrdmd); |
144 | return ret; |
145 | } |
146 | |
147 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
148 | CXD2880_IO_TGT_DMD, |
149 | 0x3c, data, sizeof(data)); |
150 | if (ret) { |
151 | slvt_unfreeze_reg(tnrdmd); |
152 | return ret; |
153 | } |
154 | |
155 | if (!(data[0] & 0x01)) { |
156 | slvt_unfreeze_reg(tnrdmd); |
157 | return -EAGAIN; |
158 | } |
159 | *pre_bit_err = |
160 | ((data[1] & 0x0f) << 24) | (data[2] << 16) | (data[3] << 8) | data[4]; |
161 | |
162 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
163 | CXD2880_IO_TGT_DMD, |
164 | 0xa0, data, 1); |
165 | if (ret) { |
166 | slvt_unfreeze_reg(tnrdmd); |
167 | return ret; |
168 | } |
169 | |
170 | if (((enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03)) == |
171 | CXD2880_DVBT2_FEC_LDPC_16K) |
172 | n_ldpc = 16200; |
173 | else |
174 | n_ldpc = 64800; |
175 | slvt_unfreeze_reg(tnrdmd); |
176 | |
177 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
178 | CXD2880_IO_TGT_DMD, |
179 | 0x00, 0x20); |
180 | if (ret) |
181 | return ret; |
182 | |
183 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
184 | CXD2880_IO_TGT_DMD, |
185 | 0x6f, data, 1); |
186 | if (ret) |
187 | return ret; |
188 | |
189 | period_exp = data[0] & 0x0f; |
190 | |
191 | *pre_bit_count = (1U << period_exp) * n_ldpc; |
192 | |
193 | return 0; |
194 | } |
195 | |
196 | static int cxd2880_post_bit_err_t(struct cxd2880_tnrdmd *tnrdmd, |
197 | u32 *post_bit_err, |
198 | u32 *post_bit_count) |
199 | { |
200 | u8 rdata[3]; |
201 | u32 bit_error = 0; |
202 | u32 period_exp = 0; |
203 | int ret; |
204 | |
205 | if (!tnrdmd || !post_bit_err || !post_bit_count) |
206 | return -EINVAL; |
207 | |
208 | if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
209 | return -EINVAL; |
210 | |
211 | if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
212 | return -EINVAL; |
213 | |
214 | if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) |
215 | return -EINVAL; |
216 | |
217 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
218 | CXD2880_IO_TGT_DMD, |
219 | 0x00, 0x0d); |
220 | if (ret) |
221 | return ret; |
222 | |
223 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
224 | CXD2880_IO_TGT_DMD, |
225 | 0x15, rdata, 3); |
226 | if (ret) |
227 | return ret; |
228 | |
229 | if ((rdata[0] & 0x40) == 0) |
230 | return -EAGAIN; |
231 | |
232 | *post_bit_err = ((rdata[0] & 0x3f) << 16) | (rdata[1] << 8) | rdata[2]; |
233 | |
234 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
235 | CXD2880_IO_TGT_DMD, |
236 | 0x00, 0x10); |
237 | if (ret) |
238 | return ret; |
239 | |
240 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
241 | CXD2880_IO_TGT_DMD, |
242 | 0x60, rdata, 1); |
243 | if (ret) |
244 | return ret; |
245 | |
246 | period_exp = (rdata[0] & 0x1f); |
247 | |
248 | if (period_exp <= 11 && (bit_error > (1U << period_exp) * 204 * 8)) |
249 | return -EAGAIN; |
250 | |
251 | *post_bit_count = (1U << period_exp) * 204 * 8; |
252 | |
253 | return 0; |
254 | } |
255 | |
256 | static int cxd2880_post_bit_err_t2(struct cxd2880_tnrdmd *tnrdmd, |
257 | u32 *post_bit_err, |
258 | u32 *post_bit_count) |
259 | { |
260 | u32 period_exp = 0; |
261 | u32 n_bch = 0; |
262 | u8 data[3]; |
263 | enum cxd2880_dvbt2_plp_fec plp_fec_type = |
264 | CXD2880_DVBT2_FEC_LDPC_16K; |
265 | enum cxd2880_dvbt2_plp_code_rate plp_code_rate = |
266 | CXD2880_DVBT2_R1_2; |
267 | int ret; |
268 | static const u16 n_bch_bits_lookup[2][8] = { |
269 | {7200, 9720, 10800, 11880, 12600, 13320, 5400, 6480}, |
270 | {32400, 38880, 43200, 48600, 51840, 54000, 21600, 25920} |
271 | }; |
272 | |
273 | if (!tnrdmd || !post_bit_err || !post_bit_count) |
274 | return -EINVAL; |
275 | |
276 | if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
277 | return -EINVAL; |
278 | |
279 | if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
280 | return -EINVAL; |
281 | |
282 | if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) |
283 | return -EINVAL; |
284 | |
285 | ret = slvt_freeze_reg(tnr_dmd: tnrdmd); |
286 | if (ret) |
287 | return ret; |
288 | |
289 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
290 | CXD2880_IO_TGT_DMD, |
291 | 0x00, 0x0b); |
292 | if (ret) { |
293 | slvt_unfreeze_reg(tnrdmd); |
294 | return ret; |
295 | } |
296 | |
297 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
298 | CXD2880_IO_TGT_DMD, |
299 | 0x15, data, 3); |
300 | if (ret) { |
301 | slvt_unfreeze_reg(tnrdmd); |
302 | return ret; |
303 | } |
304 | |
305 | if (!(data[0] & 0x40)) { |
306 | slvt_unfreeze_reg(tnrdmd); |
307 | return -EAGAIN; |
308 | } |
309 | |
310 | *post_bit_err = |
311 | ((data[0] & 0x3f) << 16) | (data[1] << 8) | data[2]; |
312 | |
313 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
314 | CXD2880_IO_TGT_DMD, |
315 | 0x9d, data, 1); |
316 | if (ret) { |
317 | slvt_unfreeze_reg(tnrdmd); |
318 | return ret; |
319 | } |
320 | |
321 | plp_code_rate = |
322 | (enum cxd2880_dvbt2_plp_code_rate)(data[0] & 0x07); |
323 | |
324 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
325 | CXD2880_IO_TGT_DMD, |
326 | 0xa0, data, 1); |
327 | if (ret) { |
328 | slvt_unfreeze_reg(tnrdmd); |
329 | return ret; |
330 | } |
331 | |
332 | plp_fec_type = (enum cxd2880_dvbt2_plp_fec)(data[0] & 0x03); |
333 | |
334 | slvt_unfreeze_reg(tnrdmd); |
335 | |
336 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
337 | CXD2880_IO_TGT_DMD, |
338 | 0x00, 0x20); |
339 | if (ret) |
340 | return ret; |
341 | |
342 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
343 | CXD2880_IO_TGT_DMD, |
344 | 0x72, data, 1); |
345 | if (ret) |
346 | return ret; |
347 | |
348 | period_exp = data[0] & 0x0f; |
349 | |
350 | if (plp_fec_type > CXD2880_DVBT2_FEC_LDPC_64K || |
351 | plp_code_rate > CXD2880_DVBT2_R2_5) |
352 | return -EAGAIN; |
353 | |
354 | n_bch = n_bch_bits_lookup[plp_fec_type][plp_code_rate]; |
355 | |
356 | if (*post_bit_err > ((1U << period_exp) * n_bch)) |
357 | return -EAGAIN; |
358 | |
359 | *post_bit_count = (1U << period_exp) * n_bch; |
360 | |
361 | return 0; |
362 | } |
363 | |
364 | static int cxd2880_read_block_err_t(struct cxd2880_tnrdmd *tnrdmd, |
365 | u32 *block_err, |
366 | u32 *block_count) |
367 | { |
368 | u8 rdata[3]; |
369 | int ret; |
370 | |
371 | if (!tnrdmd || !block_err || !block_count) |
372 | return -EINVAL; |
373 | |
374 | if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
375 | return -EINVAL; |
376 | |
377 | if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
378 | return -EINVAL; |
379 | |
380 | if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT) |
381 | return -EINVAL; |
382 | |
383 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
384 | CXD2880_IO_TGT_DMD, |
385 | 0x00, 0x0d); |
386 | if (ret) |
387 | return ret; |
388 | |
389 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
390 | CXD2880_IO_TGT_DMD, |
391 | 0x18, rdata, 3); |
392 | if (ret) |
393 | return ret; |
394 | |
395 | if ((rdata[0] & 0x01) == 0) |
396 | return -EAGAIN; |
397 | |
398 | *block_err = (rdata[1] << 8) | rdata[2]; |
399 | |
400 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
401 | CXD2880_IO_TGT_DMD, |
402 | 0x00, 0x10); |
403 | if (ret) |
404 | return ret; |
405 | |
406 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
407 | CXD2880_IO_TGT_DMD, |
408 | 0x5c, rdata, 1); |
409 | if (ret) |
410 | return ret; |
411 | |
412 | *block_count = 1U << (rdata[0] & 0x0f); |
413 | |
414 | if ((*block_count == 0) || (*block_err > *block_count)) |
415 | return -EAGAIN; |
416 | |
417 | return 0; |
418 | } |
419 | |
420 | static int cxd2880_read_block_err_t2(struct cxd2880_tnrdmd *tnrdmd, |
421 | u32 *block_err, |
422 | u32 *block_count) |
423 | { |
424 | u8 rdata[3]; |
425 | int ret; |
426 | |
427 | if (!tnrdmd || !block_err || !block_count) |
428 | return -EINVAL; |
429 | |
430 | if (tnrdmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
431 | return -EINVAL; |
432 | |
433 | if (tnrdmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
434 | return -EINVAL; |
435 | if (tnrdmd->sys != CXD2880_DTV_SYS_DVBT2) |
436 | return -EINVAL; |
437 | |
438 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
439 | CXD2880_IO_TGT_DMD, |
440 | 0x00, 0x0b); |
441 | if (ret) |
442 | return ret; |
443 | |
444 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
445 | CXD2880_IO_TGT_DMD, |
446 | 0x18, rdata, 3); |
447 | if (ret) |
448 | return ret; |
449 | |
450 | if ((rdata[0] & 0x01) == 0) |
451 | return -EAGAIN; |
452 | |
453 | *block_err = (rdata[1] << 8) | rdata[2]; |
454 | |
455 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
456 | CXD2880_IO_TGT_DMD, |
457 | 0x00, 0x24); |
458 | if (ret) |
459 | return ret; |
460 | |
461 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
462 | CXD2880_IO_TGT_DMD, |
463 | 0xdc, rdata, 1); |
464 | if (ret) |
465 | return ret; |
466 | |
467 | *block_count = 1U << (rdata[0] & 0x0f); |
468 | |
469 | if ((*block_count == 0) || (*block_err > *block_count)) |
470 | return -EAGAIN; |
471 | |
472 | return 0; |
473 | } |
474 | |
475 | static void cxd2880_release(struct dvb_frontend *fe) |
476 | { |
477 | struct cxd2880_priv *priv = NULL; |
478 | |
479 | if (!fe) { |
480 | pr_err("invalid arg.\n" ); |
481 | return; |
482 | } |
483 | priv = fe->demodulator_priv; |
484 | kfree(objp: priv); |
485 | } |
486 | |
487 | static int cxd2880_init(struct dvb_frontend *fe) |
488 | { |
489 | int ret; |
490 | struct cxd2880_priv *priv = NULL; |
491 | struct cxd2880_tnrdmd_create_param create_param; |
492 | |
493 | if (!fe) { |
494 | pr_err("invalid arg.\n" ); |
495 | return -EINVAL; |
496 | } |
497 | |
498 | priv = fe->demodulator_priv; |
499 | |
500 | create_param.ts_output_if = CXD2880_TNRDMD_TSOUT_IF_SPI; |
501 | create_param.xtal_share_type = CXD2880_TNRDMD_XTAL_SHARE_NONE; |
502 | create_param.en_internal_ldo = 1; |
503 | create_param.xosc_cap = 18; |
504 | create_param.xosc_i = 8; |
505 | create_param.stationary_use = 1; |
506 | |
507 | mutex_lock(priv->spi_mutex); |
508 | if (priv->tnrdmd.io != &priv->regio) { |
509 | ret = cxd2880_tnrdmd_create(tnr_dmd: &priv->tnrdmd, |
510 | io: &priv->regio, create_param: &create_param); |
511 | if (ret) { |
512 | mutex_unlock(lock: priv->spi_mutex); |
513 | pr_info("cxd2880 tnrdmd create failed %d\n" , ret); |
514 | return ret; |
515 | } |
516 | } |
517 | ret = cxd2880_integ_init(tnr_dmd: &priv->tnrdmd); |
518 | if (ret) { |
519 | mutex_unlock(lock: priv->spi_mutex); |
520 | pr_err("cxd2880 integ init failed %d\n" , ret); |
521 | return ret; |
522 | } |
523 | |
524 | ret = cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
525 | id: CXD2880_TNRDMD_CFG_TSPIN_CURRENT, |
526 | value: 0x00); |
527 | if (ret) { |
528 | mutex_unlock(lock: priv->spi_mutex); |
529 | pr_err("cxd2880 set config failed %d\n" , ret); |
530 | return ret; |
531 | } |
532 | mutex_unlock(lock: priv->spi_mutex); |
533 | |
534 | pr_debug("OK.\n" ); |
535 | |
536 | return ret; |
537 | } |
538 | |
539 | static int cxd2880_sleep(struct dvb_frontend *fe) |
540 | { |
541 | int ret; |
542 | struct cxd2880_priv *priv = NULL; |
543 | |
544 | if (!fe) { |
545 | pr_err("invalid arg\n" ); |
546 | return -EINVAL; |
547 | } |
548 | |
549 | priv = fe->demodulator_priv; |
550 | |
551 | mutex_lock(priv->spi_mutex); |
552 | ret = cxd2880_tnrdmd_sleep(tnr_dmd: &priv->tnrdmd); |
553 | mutex_unlock(lock: priv->spi_mutex); |
554 | |
555 | pr_debug("tnrdmd_sleep ret %d\n" , ret); |
556 | |
557 | return ret; |
558 | } |
559 | |
560 | static int cxd2880_read_signal_strength(struct dvb_frontend *fe, |
561 | u16 *strength) |
562 | { |
563 | int ret; |
564 | struct cxd2880_priv *priv = NULL; |
565 | struct dtv_frontend_properties *c = NULL; |
566 | int level = 0; |
567 | |
568 | if (!fe || !strength) { |
569 | pr_err("invalid arg\n" ); |
570 | return -EINVAL; |
571 | } |
572 | |
573 | priv = fe->demodulator_priv; |
574 | c = &fe->dtv_property_cache; |
575 | |
576 | mutex_lock(priv->spi_mutex); |
577 | if (c->delivery_system == SYS_DVBT || |
578 | c->delivery_system == SYS_DVBT2) { |
579 | ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd: &priv->tnrdmd, rf_lvl_db: &level); |
580 | } else { |
581 | pr_debug("invalid system\n" ); |
582 | mutex_unlock(lock: priv->spi_mutex); |
583 | return -EINVAL; |
584 | } |
585 | mutex_unlock(lock: priv->spi_mutex); |
586 | |
587 | level /= 125; |
588 | /* |
589 | * level should be between -105dBm and -30dBm. |
590 | * E.g. they should be between: |
591 | * -105000/125 = -840 and -30000/125 = -240 |
592 | */ |
593 | level = clamp(level, -840, -240); |
594 | /* scale value to 0x0000-0xffff */ |
595 | *strength = ((level + 840) * 0xffff) / (-240 + 840); |
596 | |
597 | if (ret) |
598 | pr_debug("ret = %d\n" , ret); |
599 | |
600 | return ret; |
601 | } |
602 | |
603 | static int cxd2880_read_snr(struct dvb_frontend *fe, u16 *snr) |
604 | { |
605 | int ret; |
606 | int snrvalue = 0; |
607 | struct cxd2880_priv *priv = NULL; |
608 | struct dtv_frontend_properties *c = NULL; |
609 | |
610 | if (!fe || !snr) { |
611 | pr_err("invalid arg\n" ); |
612 | return -EINVAL; |
613 | } |
614 | |
615 | priv = fe->demodulator_priv; |
616 | c = &fe->dtv_property_cache; |
617 | |
618 | mutex_lock(priv->spi_mutex); |
619 | if (c->delivery_system == SYS_DVBT) { |
620 | ret = cxd2880_tnrdmd_dvbt_mon_snr(tnr_dmd: &priv->tnrdmd, |
621 | snr: &snrvalue); |
622 | } else if (c->delivery_system == SYS_DVBT2) { |
623 | ret = cxd2880_tnrdmd_dvbt2_mon_snr(tnr_dmd: &priv->tnrdmd, |
624 | snr: &snrvalue); |
625 | } else { |
626 | pr_err("invalid system\n" ); |
627 | mutex_unlock(lock: priv->spi_mutex); |
628 | return -EINVAL; |
629 | } |
630 | mutex_unlock(lock: priv->spi_mutex); |
631 | |
632 | if (snrvalue < 0) |
633 | snrvalue = 0; |
634 | *snr = snrvalue; |
635 | |
636 | if (ret) |
637 | pr_debug("ret = %d\n" , ret); |
638 | |
639 | return ret; |
640 | } |
641 | |
642 | static int cxd2880_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks) |
643 | { |
644 | int ret; |
645 | struct cxd2880_priv *priv = NULL; |
646 | struct dtv_frontend_properties *c = NULL; |
647 | |
648 | if (!fe || !ucblocks) { |
649 | pr_err("invalid arg\n" ); |
650 | return -EINVAL; |
651 | } |
652 | |
653 | priv = fe->demodulator_priv; |
654 | c = &fe->dtv_property_cache; |
655 | |
656 | mutex_lock(priv->spi_mutex); |
657 | if (c->delivery_system == SYS_DVBT) { |
658 | ret = cxd2880_tnrdmd_dvbt_mon_packet_error_number(tnr_dmd: &priv->tnrdmd, |
659 | pen: ucblocks); |
660 | } else if (c->delivery_system == SYS_DVBT2) { |
661 | ret = cxd2880_tnrdmd_dvbt2_mon_packet_error_number(tnr_dmd: &priv->tnrdmd, |
662 | pen: ucblocks); |
663 | } else { |
664 | pr_err("invalid system\n" ); |
665 | mutex_unlock(lock: priv->spi_mutex); |
666 | return -EINVAL; |
667 | } |
668 | mutex_unlock(lock: priv->spi_mutex); |
669 | |
670 | if (ret) |
671 | pr_debug("ret = %d\n" , ret); |
672 | |
673 | return ret; |
674 | } |
675 | |
676 | static int cxd2880_read_ber(struct dvb_frontend *fe, u32 *ber) |
677 | { |
678 | *ber = 0; |
679 | |
680 | return 0; |
681 | } |
682 | |
683 | static int cxd2880_set_ber_per_period_t(struct dvb_frontend *fe) |
684 | { |
685 | int ret; |
686 | struct cxd2880_priv *priv; |
687 | struct cxd2880_dvbt_tpsinfo info; |
688 | enum cxd2880_dtv_bandwidth bw; |
689 | u32 pre_ber_rate = 0; |
690 | u32 post_ber_rate = 0; |
691 | u32 ucblock_rate = 0; |
692 | u32 mes_exp = 0; |
693 | static const int cr_table[5] = {31500, 42000, 47250, 52500, 55125}; |
694 | static const int denominator_tbl[4] = {125664, 129472, 137088, 152320}; |
695 | |
696 | if (!fe) { |
697 | pr_err("invalid arg\n" ); |
698 | return -EINVAL; |
699 | } |
700 | |
701 | priv = fe->demodulator_priv; |
702 | bw = priv->dvbt_tune_param.bandwidth; |
703 | |
704 | ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd: &priv->tnrdmd, |
705 | info: &info); |
706 | if (ret) { |
707 | pr_err("tps monitor error ret = %d\n" , ret); |
708 | info.hierarchy = CXD2880_DVBT_HIERARCHY_NON; |
709 | info.constellation = CXD2880_DVBT_CONSTELLATION_QPSK; |
710 | info.guard = CXD2880_DVBT_GUARD_1_4; |
711 | info.rate_hp = CXD2880_DVBT_CODERATE_1_2; |
712 | info.rate_lp = CXD2880_DVBT_CODERATE_1_2; |
713 | } |
714 | |
715 | if (info.hierarchy == CXD2880_DVBT_HIERARCHY_NON) { |
716 | pre_ber_rate = 63000000 * bw * (info.constellation * 2 + 2) / |
717 | denominator_tbl[info.guard]; |
718 | |
719 | post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * |
720 | (info.constellation * 2 + 2) / |
721 | denominator_tbl[info.guard]; |
722 | |
723 | ucblock_rate = 875 * cr_table[info.rate_hp] * bw * |
724 | (info.constellation * 2 + 2) / |
725 | denominator_tbl[info.guard]; |
726 | } else { |
727 | u8 data = 0; |
728 | struct cxd2880_tnrdmd *tnrdmd = &priv->tnrdmd; |
729 | |
730 | ret = tnrdmd->io->write_reg(tnrdmd->io, |
731 | CXD2880_IO_TGT_DMD, |
732 | 0x00, 0x10); |
733 | if (!ret) { |
734 | ret = tnrdmd->io->read_regs(tnrdmd->io, |
735 | CXD2880_IO_TGT_DMD, |
736 | 0x67, &data, 1); |
737 | if (ret) |
738 | data = 0x00; |
739 | } else { |
740 | data = 0x00; |
741 | } |
742 | |
743 | if (data & 0x01) { /* Low priority */ |
744 | pre_ber_rate = |
745 | 63000000 * bw * (info.constellation * 2 + 2) / |
746 | denominator_tbl[info.guard]; |
747 | |
748 | post_ber_rate = 1000 * cr_table[info.rate_lp] * bw * |
749 | (info.constellation * 2 + 2) / |
750 | denominator_tbl[info.guard]; |
751 | |
752 | ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_lp] * |
753 | bw * (info.constellation * 2 + 2) / |
754 | denominator_tbl[info.guard]; |
755 | } else { /* High priority */ |
756 | pre_ber_rate = |
757 | 63000000 * bw * 2 / denominator_tbl[info.guard]; |
758 | |
759 | post_ber_rate = 1000 * cr_table[info.rate_hp] * bw * 2 / |
760 | denominator_tbl[info.guard]; |
761 | |
762 | ucblock_rate = (1000 * 7 / 8) * cr_table[info.rate_hp] * |
763 | bw * 2 / denominator_tbl[info.guard]; |
764 | } |
765 | } |
766 | |
767 | mes_exp = pre_ber_rate < 8192 ? 8 : intlog2(value: pre_ber_rate) >> 24; |
768 | priv->pre_ber_interval = |
769 | ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / |
770 | pre_ber_rate; |
771 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
772 | id: CXD2880_TNRDMD_CFG_DVBT_VBER_PERIOD, |
773 | value: mes_exp == 8 ? 0 : mes_exp - 12); |
774 | |
775 | mes_exp = intlog2(value: post_ber_rate) >> 24; |
776 | priv->post_ber_interval = |
777 | ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / |
778 | post_ber_rate; |
779 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
780 | id: CXD2880_TNRDMD_CFG_DVBT_BERN_PERIOD, |
781 | value: mes_exp); |
782 | |
783 | mes_exp = intlog2(value: ucblock_rate) >> 24; |
784 | priv->ucblock_interval = |
785 | ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / |
786 | ucblock_rate; |
787 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
788 | id: CXD2880_TNRDMD_CFG_DVBT_PER_MES, |
789 | value: mes_exp); |
790 | |
791 | return 0; |
792 | } |
793 | |
794 | static int cxd2880_set_ber_per_period_t2(struct dvb_frontend *fe) |
795 | { |
796 | int ret; |
797 | struct cxd2880_priv *priv; |
798 | struct cxd2880_dvbt2_l1pre l1pre; |
799 | struct cxd2880_dvbt2_l1post l1post; |
800 | struct cxd2880_dvbt2_plp plp; |
801 | struct cxd2880_dvbt2_bbheader ; |
802 | enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; |
803 | u32 pre_ber_rate = 0; |
804 | u32 post_ber_rate = 0; |
805 | u32 ucblock_rate = 0; |
806 | u32 mes_exp = 0; |
807 | u32 term_a = 0; |
808 | u32 term_b = 0; |
809 | u32 denominator = 0; |
810 | static const u32 gi_tbl[7] = {32, 64, 128, 256, 8, 152, 76}; |
811 | static const u8 n_tbl[6] = {8, 2, 4, 16, 1, 1}; |
812 | static const u8 mode_tbl[6] = {2, 8, 4, 1, 16, 32}; |
813 | static const u32 kbch_tbl[2][8] = { |
814 | {6952, 9472, 10552, 11632, 12352, 13072, 5152, 6232}, |
815 | {32128, 38608, 42960, 48328, 51568, 53760, 0, 0} |
816 | }; |
817 | |
818 | if (!fe) { |
819 | pr_err("invalid arg\n" ); |
820 | return -EINVAL; |
821 | } |
822 | |
823 | priv = fe->demodulator_priv; |
824 | bw = priv->dvbt2_tune_param.bandwidth; |
825 | |
826 | ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(tnr_dmd: &priv->tnrdmd, l1_pre: &l1pre); |
827 | if (ret) { |
828 | pr_info("l1 pre error\n" ); |
829 | goto error_ber_setting; |
830 | } |
831 | |
832 | ret = cxd2880_tnrdmd_dvbt2_mon_active_plp(tnr_dmd: &priv->tnrdmd, |
833 | type: CXD2880_DVBT2_PLP_DATA, plp_info: &plp); |
834 | if (ret) { |
835 | pr_info("plp info error\n" ); |
836 | goto error_ber_setting; |
837 | } |
838 | |
839 | ret = cxd2880_tnrdmd_dvbt2_mon_l1_post(tnr_dmd: &priv->tnrdmd, l1_post: &l1post); |
840 | if (ret) { |
841 | pr_info("l1 post error\n" ); |
842 | goto error_ber_setting; |
843 | } |
844 | |
845 | term_a = |
846 | (mode_tbl[l1pre.fft_mode] * (1024 + gi_tbl[l1pre.gi])) * |
847 | (l1pre.num_symbols + n_tbl[l1pre.fft_mode]) + 2048; |
848 | |
849 | if (l1pre.mixed && l1post.fef_intvl) { |
850 | term_b = (l1post.fef_length + (l1post.fef_intvl / 2)) / |
851 | l1post.fef_intvl; |
852 | } else { |
853 | term_b = 0; |
854 | } |
855 | |
856 | switch (bw) { |
857 | case CXD2880_DTV_BW_1_7_MHZ: |
858 | denominator = ((term_a + term_b) * 71 + (131 / 2)) / 131; |
859 | break; |
860 | case CXD2880_DTV_BW_5_MHZ: |
861 | denominator = ((term_a + term_b) * 7 + 20) / 40; |
862 | break; |
863 | case CXD2880_DTV_BW_6_MHZ: |
864 | denominator = ((term_a + term_b) * 7 + 24) / 48; |
865 | break; |
866 | case CXD2880_DTV_BW_7_MHZ: |
867 | denominator = ((term_a + term_b) + 4) / 8; |
868 | break; |
869 | case CXD2880_DTV_BW_8_MHZ: |
870 | default: |
871 | denominator = ((term_a + term_b) * 7 + 32) / 64; |
872 | break; |
873 | } |
874 | |
875 | if (plp.til_type && plp.til_len) { |
876 | pre_ber_rate = |
877 | (plp.num_blocks_max * 1000000 + (denominator / 2)) / |
878 | denominator; |
879 | pre_ber_rate = (pre_ber_rate + (plp.til_len / 2)) / |
880 | plp.til_len; |
881 | } else { |
882 | pre_ber_rate = |
883 | (plp.num_blocks_max * 1000000 + (denominator / 2)) / |
884 | denominator; |
885 | } |
886 | |
887 | post_ber_rate = pre_ber_rate; |
888 | |
889 | mes_exp = intlog2(value: pre_ber_rate) >> 24; |
890 | priv->pre_ber_interval = |
891 | ((1U << mes_exp) * 1000 + (pre_ber_rate / 2)) / |
892 | pre_ber_rate; |
893 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
894 | id: CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, |
895 | value: mes_exp); |
896 | |
897 | mes_exp = intlog2(value: post_ber_rate) >> 24; |
898 | priv->post_ber_interval = |
899 | ((1U << mes_exp) * 1000 + (post_ber_rate / 2)) / |
900 | post_ber_rate; |
901 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
902 | id: CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, |
903 | value: mes_exp); |
904 | |
905 | ret = cxd2880_tnrdmd_dvbt2_mon_bbheader(tnr_dmd: &priv->tnrdmd, |
906 | type: CXD2880_DVBT2_PLP_DATA, |
907 | bbheader: &bbheader); |
908 | if (ret) { |
909 | pr_info("bb header error\n" ); |
910 | goto error_ucblock_setting; |
911 | } |
912 | |
913 | if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_NM) { |
914 | if (!bbheader.issy_indicator) { |
915 | ucblock_rate = |
916 | (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + |
917 | 752) / 1504; |
918 | } else { |
919 | ucblock_rate = |
920 | (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + |
921 | 764) / 1528; |
922 | } |
923 | } else if (bbheader.plp_mode == CXD2880_DVBT2_PLP_MODE_HEM) { |
924 | ucblock_rate = |
925 | (pre_ber_rate * kbch_tbl[plp.fec][plp.plp_cr] + 748) / |
926 | 1496; |
927 | } else { |
928 | pr_info("plp mode is not Normal or HEM\n" ); |
929 | goto error_ucblock_setting; |
930 | } |
931 | |
932 | mes_exp = intlog2(value: ucblock_rate) >> 24; |
933 | priv->ucblock_interval = |
934 | ((1U << mes_exp) * 1000 + (ucblock_rate / 2)) / |
935 | ucblock_rate; |
936 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
937 | id: CXD2880_TNRDMD_CFG_DVBT2_PER_MES, |
938 | value: mes_exp); |
939 | |
940 | return 0; |
941 | |
942 | error_ber_setting: |
943 | priv->pre_ber_interval = 1000; |
944 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
945 | id: CXD2880_TNRDMD_CFG_DVBT2_LBER_MES, value: 0); |
946 | |
947 | priv->post_ber_interval = 1000; |
948 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
949 | id: CXD2880_TNRDMD_CFG_DVBT2_BBER_MES, value: 0); |
950 | |
951 | error_ucblock_setting: |
952 | priv->ucblock_interval = 1000; |
953 | cxd2880_tnrdmd_set_cfg(tnr_dmd: &priv->tnrdmd, |
954 | id: CXD2880_TNRDMD_CFG_DVBT2_PER_MES, value: 8); |
955 | |
956 | return 0; |
957 | } |
958 | |
959 | static int cxd2880_dvbt_tune(struct cxd2880_tnrdmd *tnr_dmd, |
960 | struct cxd2880_dvbt_tune_param |
961 | *tune_param) |
962 | { |
963 | int ret; |
964 | |
965 | if (!tnr_dmd || !tune_param) |
966 | return -EINVAL; |
967 | |
968 | if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
969 | return -EINVAL; |
970 | |
971 | if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && |
972 | tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
973 | return -EINVAL; |
974 | |
975 | atomic_set(v: &tnr_dmd->cancel, i: 0); |
976 | |
977 | if (tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && |
978 | tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && |
979 | tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && |
980 | tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { |
981 | return -ENOTTY; |
982 | } |
983 | |
984 | ret = cxd2880_tnrdmd_dvbt_tune1(tnr_dmd, tune_param); |
985 | if (ret) |
986 | return ret; |
987 | |
988 | usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, |
989 | CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); |
990 | |
991 | return cxd2880_tnrdmd_dvbt_tune2(tnr_dmd, tune_param); |
992 | } |
993 | |
994 | static int cxd2880_dvbt2_tune(struct cxd2880_tnrdmd *tnr_dmd, |
995 | struct cxd2880_dvbt2_tune_param |
996 | *tune_param) |
997 | { |
998 | int ret; |
999 | |
1000 | if (!tnr_dmd || !tune_param) |
1001 | return -EINVAL; |
1002 | |
1003 | if (tnr_dmd->diver_mode == CXD2880_TNRDMD_DIVERMODE_SUB) |
1004 | return -EINVAL; |
1005 | |
1006 | if (tnr_dmd->state != CXD2880_TNRDMD_STATE_SLEEP && |
1007 | tnr_dmd->state != CXD2880_TNRDMD_STATE_ACTIVE) |
1008 | return -EINVAL; |
1009 | |
1010 | atomic_set(v: &tnr_dmd->cancel, i: 0); |
1011 | |
1012 | if (tune_param->bandwidth != CXD2880_DTV_BW_1_7_MHZ && |
1013 | tune_param->bandwidth != CXD2880_DTV_BW_5_MHZ && |
1014 | tune_param->bandwidth != CXD2880_DTV_BW_6_MHZ && |
1015 | tune_param->bandwidth != CXD2880_DTV_BW_7_MHZ && |
1016 | tune_param->bandwidth != CXD2880_DTV_BW_8_MHZ) { |
1017 | return -ENOTTY; |
1018 | } |
1019 | |
1020 | if (tune_param->profile != CXD2880_DVBT2_PROFILE_BASE && |
1021 | tune_param->profile != CXD2880_DVBT2_PROFILE_LITE) |
1022 | return -EINVAL; |
1023 | |
1024 | ret = cxd2880_tnrdmd_dvbt2_tune1(tnr_dmd, tune_param); |
1025 | if (ret) |
1026 | return ret; |
1027 | |
1028 | usleep_range(CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000, |
1029 | CXD2880_TNRDMD_WAIT_AGC_STABLE * 10000 + 1000); |
1030 | |
1031 | return cxd2880_tnrdmd_dvbt2_tune2(tnr_dmd, tune_param); |
1032 | } |
1033 | |
1034 | static int cxd2880_set_frontend(struct dvb_frontend *fe) |
1035 | { |
1036 | int ret; |
1037 | struct dtv_frontend_properties *c; |
1038 | struct cxd2880_priv *priv; |
1039 | enum cxd2880_dtv_bandwidth bw = CXD2880_DTV_BW_1_7_MHZ; |
1040 | |
1041 | if (!fe) { |
1042 | pr_err("invalid arg\n" ); |
1043 | return -EINVAL; |
1044 | } |
1045 | |
1046 | priv = fe->demodulator_priv; |
1047 | c = &fe->dtv_property_cache; |
1048 | |
1049 | c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1050 | c->pre_bit_error.stat[0].uvalue = 0; |
1051 | c->pre_bit_error.len = 1; |
1052 | c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1053 | c->pre_bit_count.stat[0].uvalue = 0; |
1054 | c->pre_bit_count.len = 1; |
1055 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1056 | c->post_bit_error.stat[0].uvalue = 0; |
1057 | c->post_bit_error.len = 1; |
1058 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1059 | c->post_bit_count.stat[0].uvalue = 0; |
1060 | c->post_bit_count.len = 1; |
1061 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1062 | c->block_error.stat[0].uvalue = 0; |
1063 | c->block_error.len = 1; |
1064 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1065 | c->block_count.stat[0].uvalue = 0; |
1066 | c->block_count.len = 1; |
1067 | |
1068 | switch (c->bandwidth_hz) { |
1069 | case 1712000: |
1070 | bw = CXD2880_DTV_BW_1_7_MHZ; |
1071 | break; |
1072 | case 5000000: |
1073 | bw = CXD2880_DTV_BW_5_MHZ; |
1074 | break; |
1075 | case 6000000: |
1076 | bw = CXD2880_DTV_BW_6_MHZ; |
1077 | break; |
1078 | case 7000000: |
1079 | bw = CXD2880_DTV_BW_7_MHZ; |
1080 | break; |
1081 | case 8000000: |
1082 | bw = CXD2880_DTV_BW_8_MHZ; |
1083 | break; |
1084 | default: |
1085 | return -EINVAL; |
1086 | } |
1087 | |
1088 | priv->s = 0; |
1089 | |
1090 | pr_info("sys:%d freq:%d bw:%d\n" , |
1091 | c->delivery_system, c->frequency, bw); |
1092 | mutex_lock(priv->spi_mutex); |
1093 | if (c->delivery_system == SYS_DVBT) { |
1094 | priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT; |
1095 | priv->dvbt_tune_param.center_freq_khz = c->frequency / 1000; |
1096 | priv->dvbt_tune_param.bandwidth = bw; |
1097 | priv->dvbt_tune_param.profile = CXD2880_DVBT_PROFILE_HP; |
1098 | ret = cxd2880_dvbt_tune(tnr_dmd: &priv->tnrdmd, |
1099 | tune_param: &priv->dvbt_tune_param); |
1100 | } else if (c->delivery_system == SYS_DVBT2) { |
1101 | priv->tnrdmd.sys = CXD2880_DTV_SYS_DVBT2; |
1102 | priv->dvbt2_tune_param.center_freq_khz = c->frequency / 1000; |
1103 | priv->dvbt2_tune_param.bandwidth = bw; |
1104 | priv->dvbt2_tune_param.data_plp_id = (u16)c->stream_id; |
1105 | priv->dvbt2_tune_param.profile = CXD2880_DVBT2_PROFILE_BASE; |
1106 | ret = cxd2880_dvbt2_tune(tnr_dmd: &priv->tnrdmd, |
1107 | tune_param: &priv->dvbt2_tune_param); |
1108 | } else { |
1109 | pr_err("invalid system\n" ); |
1110 | mutex_unlock(lock: priv->spi_mutex); |
1111 | return -EINVAL; |
1112 | } |
1113 | mutex_unlock(lock: priv->spi_mutex); |
1114 | |
1115 | pr_info("tune result %d\n" , ret); |
1116 | |
1117 | return ret; |
1118 | } |
1119 | |
1120 | static int cxd2880_get_stats(struct dvb_frontend *fe, |
1121 | enum fe_status status) |
1122 | { |
1123 | struct cxd2880_priv *priv = NULL; |
1124 | struct dtv_frontend_properties *c = NULL; |
1125 | u32 pre_bit_err = 0, pre_bit_count = 0; |
1126 | u32 post_bit_err = 0, post_bit_count = 0; |
1127 | u32 block_err = 0, block_count = 0; |
1128 | int ret; |
1129 | |
1130 | if (!fe) { |
1131 | pr_err("invalid arg\n" ); |
1132 | return -EINVAL; |
1133 | } |
1134 | |
1135 | priv = fe->demodulator_priv; |
1136 | c = &fe->dtv_property_cache; |
1137 | |
1138 | if (!(status & FE_HAS_LOCK) || !(status & FE_HAS_CARRIER)) { |
1139 | c->pre_bit_error.len = 1; |
1140 | c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1141 | c->pre_bit_count.len = 1; |
1142 | c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1143 | c->post_bit_error.len = 1; |
1144 | c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1145 | c->post_bit_count.len = 1; |
1146 | c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1147 | c->block_error.len = 1; |
1148 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1149 | c->block_count.len = 1; |
1150 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1151 | |
1152 | return 0; |
1153 | } |
1154 | |
1155 | if (time_after(jiffies, priv->pre_ber_update)) { |
1156 | priv->pre_ber_update = |
1157 | jiffies + msecs_to_jiffies(m: priv->pre_ber_interval); |
1158 | if (c->delivery_system == SYS_DVBT) { |
1159 | mutex_lock(priv->spi_mutex); |
1160 | ret = cxd2880_pre_bit_err_t(tnrdmd: &priv->tnrdmd, |
1161 | pre_bit_err: &pre_bit_err, |
1162 | pre_bit_count: &pre_bit_count); |
1163 | mutex_unlock(lock: priv->spi_mutex); |
1164 | } else if (c->delivery_system == SYS_DVBT2) { |
1165 | mutex_lock(priv->spi_mutex); |
1166 | ret = cxd2880_pre_bit_err_t2(tnrdmd: &priv->tnrdmd, |
1167 | pre_bit_err: &pre_bit_err, |
1168 | pre_bit_count: &pre_bit_count); |
1169 | mutex_unlock(lock: priv->spi_mutex); |
1170 | } else { |
1171 | return -EINVAL; |
1172 | } |
1173 | |
1174 | if (!ret) { |
1175 | c->pre_bit_error.len = 1; |
1176 | c->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
1177 | c->pre_bit_error.stat[0].uvalue += pre_bit_err; |
1178 | c->pre_bit_count.len = 1; |
1179 | c->pre_bit_count.stat[0].scale = FE_SCALE_COUNTER; |
1180 | c->pre_bit_count.stat[0].uvalue += pre_bit_count; |
1181 | } else { |
1182 | c->pre_bit_error.len = 1; |
1183 | c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1184 | c->pre_bit_count.len = 1; |
1185 | c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1186 | pr_debug("pre_bit_error_t failed %d\n" , ret); |
1187 | } |
1188 | } |
1189 | |
1190 | if (time_after(jiffies, priv->post_ber_update)) { |
1191 | priv->post_ber_update = |
1192 | jiffies + msecs_to_jiffies(m: priv->post_ber_interval); |
1193 | if (c->delivery_system == SYS_DVBT) { |
1194 | mutex_lock(priv->spi_mutex); |
1195 | ret = cxd2880_post_bit_err_t(tnrdmd: &priv->tnrdmd, |
1196 | post_bit_err: &post_bit_err, |
1197 | post_bit_count: &post_bit_count); |
1198 | mutex_unlock(lock: priv->spi_mutex); |
1199 | } else if (c->delivery_system == SYS_DVBT2) { |
1200 | mutex_lock(priv->spi_mutex); |
1201 | ret = cxd2880_post_bit_err_t2(tnrdmd: &priv->tnrdmd, |
1202 | post_bit_err: &post_bit_err, |
1203 | post_bit_count: &post_bit_count); |
1204 | mutex_unlock(lock: priv->spi_mutex); |
1205 | } else { |
1206 | return -EINVAL; |
1207 | } |
1208 | |
1209 | if (!ret) { |
1210 | c->post_bit_error.len = 1; |
1211 | c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; |
1212 | c->post_bit_error.stat[0].uvalue += post_bit_err; |
1213 | c->post_bit_count.len = 1; |
1214 | c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; |
1215 | c->post_bit_count.stat[0].uvalue += post_bit_count; |
1216 | } else { |
1217 | c->post_bit_error.len = 1; |
1218 | c->post_bit_error.stat[0].scale = |
1219 | FE_SCALE_NOT_AVAILABLE; |
1220 | c->post_bit_count.len = 1; |
1221 | c->post_bit_count.stat[0].scale = |
1222 | FE_SCALE_NOT_AVAILABLE; |
1223 | pr_debug("post_bit_err_t %d\n" , ret); |
1224 | } |
1225 | } |
1226 | |
1227 | if (time_after(jiffies, priv->ucblock_update)) { |
1228 | priv->ucblock_update = |
1229 | jiffies + msecs_to_jiffies(m: priv->ucblock_interval); |
1230 | if (c->delivery_system == SYS_DVBT) { |
1231 | mutex_lock(priv->spi_mutex); |
1232 | ret = cxd2880_read_block_err_t(tnrdmd: &priv->tnrdmd, |
1233 | block_err: &block_err, |
1234 | block_count: &block_count); |
1235 | mutex_unlock(lock: priv->spi_mutex); |
1236 | } else if (c->delivery_system == SYS_DVBT2) { |
1237 | mutex_lock(priv->spi_mutex); |
1238 | ret = cxd2880_read_block_err_t2(tnrdmd: &priv->tnrdmd, |
1239 | block_err: &block_err, |
1240 | block_count: &block_count); |
1241 | mutex_unlock(lock: priv->spi_mutex); |
1242 | } else { |
1243 | return -EINVAL; |
1244 | } |
1245 | if (!ret) { |
1246 | c->block_error.len = 1; |
1247 | c->block_error.stat[0].scale = FE_SCALE_COUNTER; |
1248 | c->block_error.stat[0].uvalue += block_err; |
1249 | c->block_count.len = 1; |
1250 | c->block_count.stat[0].scale = FE_SCALE_COUNTER; |
1251 | c->block_count.stat[0].uvalue += block_count; |
1252 | } else { |
1253 | c->block_error.len = 1; |
1254 | c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1255 | c->block_count.len = 1; |
1256 | c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1257 | pr_debug("read_block_err_t %d\n" , ret); |
1258 | } |
1259 | } |
1260 | |
1261 | return 0; |
1262 | } |
1263 | |
1264 | static int cxd2880_check_l1post_plp(struct dvb_frontend *fe) |
1265 | { |
1266 | u8 valid = 0; |
1267 | u8 plp_not_found; |
1268 | int ret; |
1269 | struct cxd2880_priv *priv = NULL; |
1270 | |
1271 | if (!fe) { |
1272 | pr_err("invalid arg\n" ); |
1273 | return -EINVAL; |
1274 | } |
1275 | |
1276 | priv = fe->demodulator_priv; |
1277 | |
1278 | ret = cxd2880_tnrdmd_dvbt2_check_l1post_valid(tnr_dmd: &priv->tnrdmd, |
1279 | l1_post_valid: &valid); |
1280 | if (ret) |
1281 | return ret; |
1282 | |
1283 | if (!valid) |
1284 | return -EAGAIN; |
1285 | |
1286 | ret = cxd2880_tnrdmd_dvbt2_mon_data_plp_error(tnr_dmd: &priv->tnrdmd, |
1287 | plp_error: &plp_not_found); |
1288 | if (ret) |
1289 | return ret; |
1290 | |
1291 | if (plp_not_found) { |
1292 | priv->dvbt2_tune_param.tune_info = |
1293 | CXD2880_TNRDMD_DVBT2_TUNE_INFO_INVALID_PLP_ID; |
1294 | } else { |
1295 | priv->dvbt2_tune_param.tune_info = |
1296 | CXD2880_TNRDMD_DVBT2_TUNE_INFO_OK; |
1297 | } |
1298 | |
1299 | return 0; |
1300 | } |
1301 | |
1302 | static int cxd2880_read_status(struct dvb_frontend *fe, |
1303 | enum fe_status *status) |
1304 | { |
1305 | int ret; |
1306 | u8 sync = 0; |
1307 | u8 lock = 0; |
1308 | u8 unlock = 0; |
1309 | struct cxd2880_priv *priv = NULL; |
1310 | struct dtv_frontend_properties *c = NULL; |
1311 | |
1312 | if (!fe || !status) { |
1313 | pr_err("invalid arg\n" ); |
1314 | return -EINVAL; |
1315 | } |
1316 | |
1317 | priv = fe->demodulator_priv; |
1318 | c = &fe->dtv_property_cache; |
1319 | *status = 0; |
1320 | |
1321 | if (priv->tnrdmd.state == CXD2880_TNRDMD_STATE_ACTIVE) { |
1322 | mutex_lock(priv->spi_mutex); |
1323 | if (c->delivery_system == SYS_DVBT) { |
1324 | ret = cxd2880_tnrdmd_dvbt_mon_sync_stat(tnr_dmd: &priv->tnrdmd, |
1325 | sync_stat: &sync, |
1326 | ts_lock_stat: &lock, |
1327 | unlock_detected: &unlock); |
1328 | } else if (c->delivery_system == SYS_DVBT2) { |
1329 | ret = cxd2880_tnrdmd_dvbt2_mon_sync_stat(tnr_dmd: &priv->tnrdmd, |
1330 | sync_stat: &sync, |
1331 | ts_lock_stat: &lock, |
1332 | unlock_detected: &unlock); |
1333 | } else { |
1334 | pr_err("invalid system" ); |
1335 | mutex_unlock(lock: priv->spi_mutex); |
1336 | return -EINVAL; |
1337 | } |
1338 | |
1339 | mutex_unlock(lock: priv->spi_mutex); |
1340 | if (ret) { |
1341 | pr_err("failed. sys = %d\n" , priv->tnrdmd.sys); |
1342 | return ret; |
1343 | } |
1344 | |
1345 | if (sync == 6) { |
1346 | *status = FE_HAS_SIGNAL | |
1347 | FE_HAS_CARRIER; |
1348 | } |
1349 | if (lock) |
1350 | *status |= FE_HAS_VITERBI | |
1351 | FE_HAS_SYNC | |
1352 | FE_HAS_LOCK; |
1353 | } |
1354 | |
1355 | pr_debug("status %d\n" , *status); |
1356 | |
1357 | if (priv->s == 0 && (*status & FE_HAS_LOCK) && |
1358 | (*status & FE_HAS_CARRIER)) { |
1359 | mutex_lock(priv->spi_mutex); |
1360 | if (c->delivery_system == SYS_DVBT) { |
1361 | ret = cxd2880_set_ber_per_period_t(fe); |
1362 | priv->s = *status; |
1363 | } else if (c->delivery_system == SYS_DVBT2) { |
1364 | ret = cxd2880_check_l1post_plp(fe); |
1365 | if (!ret) { |
1366 | ret = cxd2880_set_ber_per_period_t2(fe); |
1367 | priv->s = *status; |
1368 | } |
1369 | } else { |
1370 | pr_err("invalid system\n" ); |
1371 | mutex_unlock(lock: priv->spi_mutex); |
1372 | return -EINVAL; |
1373 | } |
1374 | mutex_unlock(lock: priv->spi_mutex); |
1375 | } |
1376 | |
1377 | cxd2880_get_stats(fe, status: *status); |
1378 | return 0; |
1379 | } |
1380 | |
1381 | static int cxd2880_tune(struct dvb_frontend *fe, |
1382 | bool retune, |
1383 | unsigned int mode_flags, |
1384 | unsigned int *delay, |
1385 | enum fe_status *status) |
1386 | { |
1387 | int ret; |
1388 | |
1389 | if (!fe || !delay || !status) { |
1390 | pr_err("invalid arg." ); |
1391 | return -EINVAL; |
1392 | } |
1393 | |
1394 | if (retune) { |
1395 | ret = cxd2880_set_frontend(fe); |
1396 | if (ret) { |
1397 | pr_err("cxd2880_set_frontend failed %d\n" , ret); |
1398 | return ret; |
1399 | } |
1400 | } |
1401 | |
1402 | *delay = HZ / 5; |
1403 | |
1404 | return cxd2880_read_status(fe, status); |
1405 | } |
1406 | |
1407 | static int cxd2880_get_frontend_t(struct dvb_frontend *fe, |
1408 | struct dtv_frontend_properties *c) |
1409 | { |
1410 | int ret; |
1411 | struct cxd2880_priv *priv = NULL; |
1412 | enum cxd2880_dvbt_mode mode = CXD2880_DVBT_MODE_2K; |
1413 | enum cxd2880_dvbt_guard guard = CXD2880_DVBT_GUARD_1_32; |
1414 | struct cxd2880_dvbt_tpsinfo tps; |
1415 | enum cxd2880_tnrdmd_spectrum_sense sense; |
1416 | u16 snr = 0; |
1417 | int strength = 0; |
1418 | |
1419 | if (!fe || !c) { |
1420 | pr_err("invalid arg\n" ); |
1421 | return -EINVAL; |
1422 | } |
1423 | |
1424 | priv = fe->demodulator_priv; |
1425 | |
1426 | mutex_lock(priv->spi_mutex); |
1427 | ret = cxd2880_tnrdmd_dvbt_mon_mode_guard(tnr_dmd: &priv->tnrdmd, |
1428 | mode: &mode, guard: &guard); |
1429 | mutex_unlock(lock: priv->spi_mutex); |
1430 | if (!ret) { |
1431 | switch (mode) { |
1432 | case CXD2880_DVBT_MODE_2K: |
1433 | c->transmission_mode = TRANSMISSION_MODE_2K; |
1434 | break; |
1435 | case CXD2880_DVBT_MODE_8K: |
1436 | c->transmission_mode = TRANSMISSION_MODE_8K; |
1437 | break; |
1438 | default: |
1439 | c->transmission_mode = TRANSMISSION_MODE_2K; |
1440 | pr_debug("transmission mode is invalid %d\n" , mode); |
1441 | break; |
1442 | } |
1443 | switch (guard) { |
1444 | case CXD2880_DVBT_GUARD_1_32: |
1445 | c->guard_interval = GUARD_INTERVAL_1_32; |
1446 | break; |
1447 | case CXD2880_DVBT_GUARD_1_16: |
1448 | c->guard_interval = GUARD_INTERVAL_1_16; |
1449 | break; |
1450 | case CXD2880_DVBT_GUARD_1_8: |
1451 | c->guard_interval = GUARD_INTERVAL_1_8; |
1452 | break; |
1453 | case CXD2880_DVBT_GUARD_1_4: |
1454 | c->guard_interval = GUARD_INTERVAL_1_4; |
1455 | break; |
1456 | default: |
1457 | c->guard_interval = GUARD_INTERVAL_1_32; |
1458 | pr_debug("guard interval is invalid %d\n" , |
1459 | guard); |
1460 | break; |
1461 | } |
1462 | } else { |
1463 | c->transmission_mode = TRANSMISSION_MODE_2K; |
1464 | c->guard_interval = GUARD_INTERVAL_1_32; |
1465 | pr_debug("ModeGuard err %d\n" , ret); |
1466 | } |
1467 | |
1468 | mutex_lock(priv->spi_mutex); |
1469 | ret = cxd2880_tnrdmd_dvbt_mon_tps_info(tnr_dmd: &priv->tnrdmd, info: &tps); |
1470 | mutex_unlock(lock: priv->spi_mutex); |
1471 | if (!ret) { |
1472 | switch (tps.hierarchy) { |
1473 | case CXD2880_DVBT_HIERARCHY_NON: |
1474 | c->hierarchy = HIERARCHY_NONE; |
1475 | break; |
1476 | case CXD2880_DVBT_HIERARCHY_1: |
1477 | c->hierarchy = HIERARCHY_1; |
1478 | break; |
1479 | case CXD2880_DVBT_HIERARCHY_2: |
1480 | c->hierarchy = HIERARCHY_2; |
1481 | break; |
1482 | case CXD2880_DVBT_HIERARCHY_4: |
1483 | c->hierarchy = HIERARCHY_4; |
1484 | break; |
1485 | default: |
1486 | c->hierarchy = HIERARCHY_NONE; |
1487 | pr_debug("TPSInfo hierarchy is invalid %d\n" , |
1488 | tps.hierarchy); |
1489 | break; |
1490 | } |
1491 | |
1492 | switch (tps.rate_hp) { |
1493 | case CXD2880_DVBT_CODERATE_1_2: |
1494 | c->code_rate_HP = FEC_1_2; |
1495 | break; |
1496 | case CXD2880_DVBT_CODERATE_2_3: |
1497 | c->code_rate_HP = FEC_2_3; |
1498 | break; |
1499 | case CXD2880_DVBT_CODERATE_3_4: |
1500 | c->code_rate_HP = FEC_3_4; |
1501 | break; |
1502 | case CXD2880_DVBT_CODERATE_5_6: |
1503 | c->code_rate_HP = FEC_5_6; |
1504 | break; |
1505 | case CXD2880_DVBT_CODERATE_7_8: |
1506 | c->code_rate_HP = FEC_7_8; |
1507 | break; |
1508 | default: |
1509 | c->code_rate_HP = FEC_NONE; |
1510 | pr_debug("TPSInfo rateHP is invalid %d\n" , |
1511 | tps.rate_hp); |
1512 | break; |
1513 | } |
1514 | switch (tps.rate_lp) { |
1515 | case CXD2880_DVBT_CODERATE_1_2: |
1516 | c->code_rate_LP = FEC_1_2; |
1517 | break; |
1518 | case CXD2880_DVBT_CODERATE_2_3: |
1519 | c->code_rate_LP = FEC_2_3; |
1520 | break; |
1521 | case CXD2880_DVBT_CODERATE_3_4: |
1522 | c->code_rate_LP = FEC_3_4; |
1523 | break; |
1524 | case CXD2880_DVBT_CODERATE_5_6: |
1525 | c->code_rate_LP = FEC_5_6; |
1526 | break; |
1527 | case CXD2880_DVBT_CODERATE_7_8: |
1528 | c->code_rate_LP = FEC_7_8; |
1529 | break; |
1530 | default: |
1531 | c->code_rate_LP = FEC_NONE; |
1532 | pr_debug("TPSInfo rateLP is invalid %d\n" , |
1533 | tps.rate_lp); |
1534 | break; |
1535 | } |
1536 | switch (tps.constellation) { |
1537 | case CXD2880_DVBT_CONSTELLATION_QPSK: |
1538 | c->modulation = QPSK; |
1539 | break; |
1540 | case CXD2880_DVBT_CONSTELLATION_16QAM: |
1541 | c->modulation = QAM_16; |
1542 | break; |
1543 | case CXD2880_DVBT_CONSTELLATION_64QAM: |
1544 | c->modulation = QAM_64; |
1545 | break; |
1546 | default: |
1547 | c->modulation = QPSK; |
1548 | pr_debug("TPSInfo constellation is invalid %d\n" , |
1549 | tps.constellation); |
1550 | break; |
1551 | } |
1552 | } else { |
1553 | c->hierarchy = HIERARCHY_NONE; |
1554 | c->code_rate_HP = FEC_NONE; |
1555 | c->code_rate_LP = FEC_NONE; |
1556 | c->modulation = QPSK; |
1557 | pr_debug("TPS info err %d\n" , ret); |
1558 | } |
1559 | |
1560 | mutex_lock(priv->spi_mutex); |
1561 | ret = cxd2880_tnrdmd_dvbt_mon_spectrum_sense(tnr_dmd: &priv->tnrdmd, sense: &sense); |
1562 | mutex_unlock(lock: priv->spi_mutex); |
1563 | if (!ret) { |
1564 | switch (sense) { |
1565 | case CXD2880_TNRDMD_SPECTRUM_NORMAL: |
1566 | c->inversion = INVERSION_OFF; |
1567 | break; |
1568 | case CXD2880_TNRDMD_SPECTRUM_INV: |
1569 | c->inversion = INVERSION_ON; |
1570 | break; |
1571 | default: |
1572 | c->inversion = INVERSION_OFF; |
1573 | pr_debug("spectrum sense is invalid %d\n" , sense); |
1574 | break; |
1575 | } |
1576 | } else { |
1577 | c->inversion = INVERSION_OFF; |
1578 | pr_debug("spectrum_sense %d\n" , ret); |
1579 | } |
1580 | |
1581 | mutex_lock(priv->spi_mutex); |
1582 | ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd: &priv->tnrdmd, rf_lvl_db: &strength); |
1583 | mutex_unlock(lock: priv->spi_mutex); |
1584 | if (!ret) { |
1585 | c->strength.len = 1; |
1586 | c->strength.stat[0].scale = FE_SCALE_DECIBEL; |
1587 | c->strength.stat[0].svalue = strength; |
1588 | } else { |
1589 | c->strength.len = 1; |
1590 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1591 | pr_debug("mon_rf_lvl %d\n" , ret); |
1592 | } |
1593 | |
1594 | ret = cxd2880_read_snr(fe, snr: &snr); |
1595 | if (!ret) { |
1596 | c->cnr.len = 1; |
1597 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
1598 | c->cnr.stat[0].svalue = snr; |
1599 | } else { |
1600 | c->cnr.len = 1; |
1601 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1602 | pr_debug("read_snr %d\n" , ret); |
1603 | } |
1604 | |
1605 | return 0; |
1606 | } |
1607 | |
1608 | static int cxd2880_get_frontend_t2(struct dvb_frontend *fe, |
1609 | struct dtv_frontend_properties *c) |
1610 | { |
1611 | int ret; |
1612 | struct cxd2880_priv *priv = NULL; |
1613 | struct cxd2880_dvbt2_l1pre l1pre; |
1614 | enum cxd2880_dvbt2_plp_code_rate coderate; |
1615 | enum cxd2880_dvbt2_plp_constell qam; |
1616 | enum cxd2880_tnrdmd_spectrum_sense sense; |
1617 | u16 snr = 0; |
1618 | int strength = 0; |
1619 | |
1620 | if (!fe || !c) { |
1621 | pr_err("invalid arg.\n" ); |
1622 | return -EINVAL; |
1623 | } |
1624 | |
1625 | priv = fe->demodulator_priv; |
1626 | |
1627 | mutex_lock(priv->spi_mutex); |
1628 | ret = cxd2880_tnrdmd_dvbt2_mon_l1_pre(tnr_dmd: &priv->tnrdmd, l1_pre: &l1pre); |
1629 | mutex_unlock(lock: priv->spi_mutex); |
1630 | if (!ret) { |
1631 | switch (l1pre.fft_mode) { |
1632 | case CXD2880_DVBT2_M2K: |
1633 | c->transmission_mode = TRANSMISSION_MODE_2K; |
1634 | break; |
1635 | case CXD2880_DVBT2_M8K: |
1636 | c->transmission_mode = TRANSMISSION_MODE_8K; |
1637 | break; |
1638 | case CXD2880_DVBT2_M4K: |
1639 | c->transmission_mode = TRANSMISSION_MODE_4K; |
1640 | break; |
1641 | case CXD2880_DVBT2_M1K: |
1642 | c->transmission_mode = TRANSMISSION_MODE_1K; |
1643 | break; |
1644 | case CXD2880_DVBT2_M16K: |
1645 | c->transmission_mode = TRANSMISSION_MODE_16K; |
1646 | break; |
1647 | case CXD2880_DVBT2_M32K: |
1648 | c->transmission_mode = TRANSMISSION_MODE_32K; |
1649 | break; |
1650 | default: |
1651 | c->transmission_mode = TRANSMISSION_MODE_2K; |
1652 | pr_debug("L1Pre fft_mode is invalid %d\n" , |
1653 | l1pre.fft_mode); |
1654 | break; |
1655 | } |
1656 | switch (l1pre.gi) { |
1657 | case CXD2880_DVBT2_G1_32: |
1658 | c->guard_interval = GUARD_INTERVAL_1_32; |
1659 | break; |
1660 | case CXD2880_DVBT2_G1_16: |
1661 | c->guard_interval = GUARD_INTERVAL_1_16; |
1662 | break; |
1663 | case CXD2880_DVBT2_G1_8: |
1664 | c->guard_interval = GUARD_INTERVAL_1_8; |
1665 | break; |
1666 | case CXD2880_DVBT2_G1_4: |
1667 | c->guard_interval = GUARD_INTERVAL_1_4; |
1668 | break; |
1669 | case CXD2880_DVBT2_G1_128: |
1670 | c->guard_interval = GUARD_INTERVAL_1_128; |
1671 | break; |
1672 | case CXD2880_DVBT2_G19_128: |
1673 | c->guard_interval = GUARD_INTERVAL_19_128; |
1674 | break; |
1675 | case CXD2880_DVBT2_G19_256: |
1676 | c->guard_interval = GUARD_INTERVAL_19_256; |
1677 | break; |
1678 | default: |
1679 | c->guard_interval = GUARD_INTERVAL_1_32; |
1680 | pr_debug("L1Pre guard interval is invalid %d\n" , |
1681 | l1pre.gi); |
1682 | break; |
1683 | } |
1684 | } else { |
1685 | c->transmission_mode = TRANSMISSION_MODE_2K; |
1686 | c->guard_interval = GUARD_INTERVAL_1_32; |
1687 | pr_debug("L1Pre err %d\n" , ret); |
1688 | } |
1689 | |
1690 | mutex_lock(priv->spi_mutex); |
1691 | ret = cxd2880_tnrdmd_dvbt2_mon_code_rate(tnr_dmd: &priv->tnrdmd, |
1692 | type: CXD2880_DVBT2_PLP_DATA, |
1693 | code_rate: &coderate); |
1694 | mutex_unlock(lock: priv->spi_mutex); |
1695 | if (!ret) { |
1696 | switch (coderate) { |
1697 | case CXD2880_DVBT2_R1_2: |
1698 | c->fec_inner = FEC_1_2; |
1699 | break; |
1700 | case CXD2880_DVBT2_R3_5: |
1701 | c->fec_inner = FEC_3_5; |
1702 | break; |
1703 | case CXD2880_DVBT2_R2_3: |
1704 | c->fec_inner = FEC_2_3; |
1705 | break; |
1706 | case CXD2880_DVBT2_R3_4: |
1707 | c->fec_inner = FEC_3_4; |
1708 | break; |
1709 | case CXD2880_DVBT2_R4_5: |
1710 | c->fec_inner = FEC_4_5; |
1711 | break; |
1712 | case CXD2880_DVBT2_R5_6: |
1713 | c->fec_inner = FEC_5_6; |
1714 | break; |
1715 | default: |
1716 | c->fec_inner = FEC_NONE; |
1717 | pr_debug("CodeRate is invalid %d\n" , coderate); |
1718 | break; |
1719 | } |
1720 | } else { |
1721 | c->fec_inner = FEC_NONE; |
1722 | pr_debug("CodeRate %d\n" , ret); |
1723 | } |
1724 | |
1725 | mutex_lock(priv->spi_mutex); |
1726 | ret = cxd2880_tnrdmd_dvbt2_mon_qam(tnr_dmd: &priv->tnrdmd, |
1727 | type: CXD2880_DVBT2_PLP_DATA, |
1728 | qam: &qam); |
1729 | mutex_unlock(lock: priv->spi_mutex); |
1730 | if (!ret) { |
1731 | switch (qam) { |
1732 | case CXD2880_DVBT2_QPSK: |
1733 | c->modulation = QPSK; |
1734 | break; |
1735 | case CXD2880_DVBT2_QAM16: |
1736 | c->modulation = QAM_16; |
1737 | break; |
1738 | case CXD2880_DVBT2_QAM64: |
1739 | c->modulation = QAM_64; |
1740 | break; |
1741 | case CXD2880_DVBT2_QAM256: |
1742 | c->modulation = QAM_256; |
1743 | break; |
1744 | default: |
1745 | c->modulation = QPSK; |
1746 | pr_debug("QAM is invalid %d\n" , qam); |
1747 | break; |
1748 | } |
1749 | } else { |
1750 | c->modulation = QPSK; |
1751 | pr_debug("QAM %d\n" , ret); |
1752 | } |
1753 | |
1754 | mutex_lock(priv->spi_mutex); |
1755 | ret = cxd2880_tnrdmd_dvbt2_mon_spectrum_sense(tnr_dmd: &priv->tnrdmd, sense: &sense); |
1756 | mutex_unlock(lock: priv->spi_mutex); |
1757 | if (!ret) { |
1758 | switch (sense) { |
1759 | case CXD2880_TNRDMD_SPECTRUM_NORMAL: |
1760 | c->inversion = INVERSION_OFF; |
1761 | break; |
1762 | case CXD2880_TNRDMD_SPECTRUM_INV: |
1763 | c->inversion = INVERSION_ON; |
1764 | break; |
1765 | default: |
1766 | c->inversion = INVERSION_OFF; |
1767 | pr_debug("spectrum sense is invalid %d\n" , sense); |
1768 | break; |
1769 | } |
1770 | } else { |
1771 | c->inversion = INVERSION_OFF; |
1772 | pr_debug("SpectrumSense %d\n" , ret); |
1773 | } |
1774 | |
1775 | mutex_lock(priv->spi_mutex); |
1776 | ret = cxd2880_tnrdmd_mon_rf_lvl(tnr_dmd: &priv->tnrdmd, rf_lvl_db: &strength); |
1777 | mutex_unlock(lock: priv->spi_mutex); |
1778 | if (!ret) { |
1779 | c->strength.len = 1; |
1780 | c->strength.stat[0].scale = FE_SCALE_DECIBEL; |
1781 | c->strength.stat[0].svalue = strength; |
1782 | } else { |
1783 | c->strength.len = 1; |
1784 | c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1785 | pr_debug("mon_rf_lvl %d\n" , ret); |
1786 | } |
1787 | |
1788 | ret = cxd2880_read_snr(fe, snr: &snr); |
1789 | if (!ret) { |
1790 | c->cnr.len = 1; |
1791 | c->cnr.stat[0].scale = FE_SCALE_DECIBEL; |
1792 | c->cnr.stat[0].svalue = snr; |
1793 | } else { |
1794 | c->cnr.len = 1; |
1795 | c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE; |
1796 | pr_debug("read_snr %d\n" , ret); |
1797 | } |
1798 | |
1799 | return 0; |
1800 | } |
1801 | |
1802 | static int cxd2880_get_frontend(struct dvb_frontend *fe, |
1803 | struct dtv_frontend_properties *props) |
1804 | { |
1805 | int ret; |
1806 | |
1807 | if (!fe || !props) { |
1808 | pr_err("invalid arg." ); |
1809 | return -EINVAL; |
1810 | } |
1811 | |
1812 | pr_debug("system=%d\n" , fe->dtv_property_cache.delivery_system); |
1813 | switch (fe->dtv_property_cache.delivery_system) { |
1814 | case SYS_DVBT: |
1815 | ret = cxd2880_get_frontend_t(fe, c: props); |
1816 | break; |
1817 | case SYS_DVBT2: |
1818 | ret = cxd2880_get_frontend_t2(fe, c: props); |
1819 | break; |
1820 | default: |
1821 | ret = -EINVAL; |
1822 | break; |
1823 | } |
1824 | |
1825 | return ret; |
1826 | } |
1827 | |
1828 | static enum dvbfe_algo cxd2880_get_frontend_algo(struct dvb_frontend *fe) |
1829 | { |
1830 | return DVBFE_ALGO_HW; |
1831 | } |
1832 | |
1833 | static struct dvb_frontend_ops cxd2880_dvbt_t2_ops = { |
1834 | .info = { |
1835 | .name = "Sony CXD2880" , |
1836 | .frequency_min_hz = 174 * MHz, |
1837 | .frequency_max_hz = 862 * MHz, |
1838 | .frequency_stepsize_hz = 1 * kHz, |
1839 | .caps = FE_CAN_INVERSION_AUTO | |
1840 | FE_CAN_FEC_1_2 | |
1841 | FE_CAN_FEC_2_3 | |
1842 | FE_CAN_FEC_3_4 | |
1843 | FE_CAN_FEC_4_5 | |
1844 | FE_CAN_FEC_5_6 | |
1845 | FE_CAN_FEC_7_8 | |
1846 | FE_CAN_FEC_AUTO | |
1847 | FE_CAN_QPSK | |
1848 | FE_CAN_QAM_16 | |
1849 | FE_CAN_QAM_32 | |
1850 | FE_CAN_QAM_64 | |
1851 | FE_CAN_QAM_128 | |
1852 | FE_CAN_QAM_256 | |
1853 | FE_CAN_QAM_AUTO | |
1854 | FE_CAN_TRANSMISSION_MODE_AUTO | |
1855 | FE_CAN_GUARD_INTERVAL_AUTO | |
1856 | FE_CAN_2G_MODULATION | |
1857 | FE_CAN_RECOVER | |
1858 | FE_CAN_MUTE_TS, |
1859 | }, |
1860 | .delsys = { SYS_DVBT, SYS_DVBT2 }, |
1861 | |
1862 | .release = cxd2880_release, |
1863 | .init = cxd2880_init, |
1864 | .sleep = cxd2880_sleep, |
1865 | .tune = cxd2880_tune, |
1866 | .set_frontend = cxd2880_set_frontend, |
1867 | .get_frontend = cxd2880_get_frontend, |
1868 | .read_status = cxd2880_read_status, |
1869 | .read_ber = cxd2880_read_ber, |
1870 | .read_signal_strength = cxd2880_read_signal_strength, |
1871 | .read_snr = cxd2880_read_snr, |
1872 | .read_ucblocks = cxd2880_read_ucblocks, |
1873 | .get_frontend_algo = cxd2880_get_frontend_algo, |
1874 | }; |
1875 | |
1876 | struct dvb_frontend *cxd2880_attach(struct dvb_frontend *fe, |
1877 | struct cxd2880_config *cfg) |
1878 | { |
1879 | int ret; |
1880 | enum cxd2880_tnrdmd_chip_id chipid = |
1881 | CXD2880_TNRDMD_CHIP_ID_UNKNOWN; |
1882 | static struct cxd2880_priv *priv; |
1883 | u8 data = 0; |
1884 | |
1885 | if (!fe) { |
1886 | pr_err("invalid arg.\n" ); |
1887 | return NULL; |
1888 | } |
1889 | |
1890 | priv = kzalloc(size: sizeof(struct cxd2880_priv), GFP_KERNEL); |
1891 | if (!priv) |
1892 | return NULL; |
1893 | |
1894 | priv->spi = cfg->spi; |
1895 | priv->spi_mutex = cfg->spi_mutex; |
1896 | priv->spi_device.spi = cfg->spi; |
1897 | |
1898 | memcpy(&fe->ops, &cxd2880_dvbt_t2_ops, |
1899 | sizeof(struct dvb_frontend_ops)); |
1900 | |
1901 | ret = cxd2880_spi_device_initialize(spi_device: &priv->spi_device, |
1902 | mode: CXD2880_SPI_MODE_0, |
1903 | speedHz: 55000000); |
1904 | if (ret) { |
1905 | pr_err("spi_device_initialize failed. %d\n" , ret); |
1906 | kfree(objp: priv); |
1907 | return NULL; |
1908 | } |
1909 | |
1910 | ret = cxd2880_spi_device_create_spi(spi: &priv->cxd2880_spi, |
1911 | spi_device: &priv->spi_device); |
1912 | if (ret) { |
1913 | pr_err("spi_device_create_spi failed. %d\n" , ret); |
1914 | kfree(objp: priv); |
1915 | return NULL; |
1916 | } |
1917 | |
1918 | ret = cxd2880_io_spi_create(io: &priv->regio, spi: &priv->cxd2880_spi, slave_select: 0); |
1919 | if (ret) { |
1920 | pr_err("io_spi_create failed. %d\n" , ret); |
1921 | kfree(objp: priv); |
1922 | return NULL; |
1923 | } |
1924 | ret = priv->regio.write_reg(&priv->regio, |
1925 | CXD2880_IO_TGT_SYS, 0x00, 0x00); |
1926 | if (ret) { |
1927 | pr_err("set bank to 0x00 failed.\n" ); |
1928 | kfree(objp: priv); |
1929 | return NULL; |
1930 | } |
1931 | ret = priv->regio.read_regs(&priv->regio, |
1932 | CXD2880_IO_TGT_SYS, 0xfd, &data, 1); |
1933 | if (ret) { |
1934 | pr_err("read chip id failed.\n" ); |
1935 | kfree(objp: priv); |
1936 | return NULL; |
1937 | } |
1938 | |
1939 | chipid = (enum cxd2880_tnrdmd_chip_id)data; |
1940 | if (chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_0X && |
1941 | chipid != CXD2880_TNRDMD_CHIP_ID_CXD2880_ES1_11) { |
1942 | pr_err("chip id invalid.\n" ); |
1943 | kfree(objp: priv); |
1944 | return NULL; |
1945 | } |
1946 | |
1947 | fe->demodulator_priv = priv; |
1948 | pr_info("CXD2880 driver version: Ver %s\n" , |
1949 | CXD2880_TNRDMD_DRIVER_VERSION); |
1950 | |
1951 | return fe; |
1952 | } |
1953 | EXPORT_SYMBOL_GPL(cxd2880_attach); |
1954 | |
1955 | MODULE_DESCRIPTION("Sony CXD2880 DVB-T2/T tuner + demod driver" ); |
1956 | MODULE_AUTHOR("Sony Semiconductor Solutions Corporation" ); |
1957 | MODULE_LICENSE("GPL v2" ); |
1958 | |