blob: f783cf0722c99454882467a1effd93ce1c235441
1 | /* |
2 | * drivers/amlogic/atv_demod/atv_demod_ops.c |
3 | * |
4 | * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
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 of the License, or |
9 | * (at your option) any later version. |
10 | * |
11 | * This program is distributed in the hope that it will be useful, but WITHOUT |
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
14 | * more details. |
15 | * |
16 | */ |
17 | |
18 | #include <linux/types.h> |
19 | #include <linux/i2c.h> |
20 | #include <uapi/linux/dvb/frontend.h> |
21 | |
22 | #include <linux/amlogic/aml_atvdemod.h> |
23 | |
24 | #include "drivers/media/tuners/tuner-i2c.h" |
25 | #include "drivers/media/dvb-core/dvb_frontend.h" |
26 | #include "drivers/amlogic/media/vin/tvin/tvafe/tvafe_general.h" |
27 | |
28 | #include "atvdemod_func.h" |
29 | #include "atvauddemod_func.h" |
30 | #include "atv_demod_debug.h" |
31 | #include "atv_demod_driver.h" |
32 | #include "atv_demod_ops.h" |
33 | #include "atv_demod_v4l2.h" |
34 | #include "atv_demod_afc.h" |
35 | #include "atv_demod_monitor.h" |
36 | |
37 | #define DEVICE_NAME "aml_atvdemod" |
38 | |
39 | |
40 | static DEFINE_MUTEX(atv_demod_list_mutex); |
41 | static LIST_HEAD(hybrid_tuner_instance_list); |
42 | |
43 | unsigned int reg_23cf = 0x88188832; /*IIR filter*/ |
44 | unsigned int btsc_sap_mode = 1; /*0: off 1:monitor 2:auto */ |
45 | |
46 | |
47 | /* |
48 | * add interface for audio driver to get atv audio state. |
49 | * state: |
50 | * 0 - no data. |
51 | * 1 - has data. |
52 | */ |
53 | void aml_fe_get_atvaudio_state(int *state) |
54 | { |
55 | #if 0 /* delay notification stable */ |
56 | static unsigned int count; |
57 | static bool mute = true; |
58 | #endif |
59 | int av_status = 0; |
60 | int power = 0; |
61 | int vpll_lock = 0; |
62 | int line_lock = 0; |
63 | struct atv_demod_priv *priv = amlatvdemod_devp != NULL |
64 | ? amlatvdemod_devp->v4l2_fe.fe.analog_demod_priv : NULL; |
65 | |
66 | if (priv == NULL) { |
67 | pr_err("priv == NULL\n"); |
68 | *state = 0; |
69 | return; |
70 | } |
71 | |
72 | av_status = tvin_get_av_status(); |
73 | /* scan mode need mute */ |
74 | if (priv->state == ATVDEMOD_STATE_WORK |
75 | && !priv->scanning |
76 | && !priv->standby |
77 | && av_status) { |
78 | retrieve_vpll_carrier_lock(&vpll_lock); |
79 | retrieve_vpll_carrier_line_lock(&line_lock); |
80 | if ((vpll_lock == 0) && (line_lock == 0)) { |
81 | /* retrieve_vpll_carrier_audio_power(&power); */ |
82 | *state = 1; |
83 | } else { |
84 | *state = 0; |
85 | pr_audio("vpll_lock: 0x%x, line_lock: 0x%x\n", |
86 | vpll_lock, line_lock); |
87 | } |
88 | } else { |
89 | *state = 0; |
90 | pr_audio("ATV state[%d], scan[%d], standby[%d], av[%d].\n", |
91 | priv->state, priv->scanning, |
92 | priv->standby, av_status); |
93 | } |
94 | |
95 | /* If the atv signal is locked, it means there is audio data, |
96 | * so no need to check the power value. |
97 | */ |
98 | #if 0 |
99 | if (power >= 150) |
100 | *state = 1; |
101 | else |
102 | *state = 0; |
103 | #endif |
104 | #if 0 /* delay notification stable */ |
105 | if (*state) { |
106 | if (mute) { |
107 | count++; |
108 | if (count > 100) { |
109 | count = 0; |
110 | mute = false; |
111 | } else |
112 | *state = 0; |
113 | } else |
114 | count = 0; |
115 | } else { |
116 | count = 0; |
117 | mute = true; |
118 | } |
119 | #endif |
120 | pr_audio("aml_fe_get_atvaudio_state: %d, power = %d\n", |
121 | *state, power); |
122 | } |
123 | |
124 | int aml_atvdemod_get_btsc_sap_mode(void) |
125 | { |
126 | return btsc_sap_mode; |
127 | } |
128 | |
129 | int atv_demod_enter_mode(struct dvb_frontend *fe) |
130 | { |
131 | int err_code = 0; |
132 | |
133 | if (amlatvdemod_devp->pin_name != NULL) { |
134 | amlatvdemod_devp->agc_pin = |
135 | devm_pinctrl_get_select(amlatvdemod_devp->dev, |
136 | amlatvdemod_devp->pin_name); |
137 | if (IS_ERR(amlatvdemod_devp->agc_pin)) { |
138 | amlatvdemod_devp->agc_pin = NULL; |
139 | pr_err("%s: get agc pins fail\n", __func__); |
140 | } |
141 | } |
142 | |
143 | err_code = adc_set_pll_cntl(1, ADC_EN_ATV_DEMOD, NULL); |
144 | vdac_enable(1, 1); |
145 | usleep_range(2000, 2100); |
146 | atvdemod_clk_init(); |
147 | /* err_code = atvdemod_init(); */ |
148 | |
149 | if (is_meson_txlx_cpu() || is_meson_txhd_cpu() || is_meson_tl1_cpu()) { |
150 | aud_demod_clk_gate(1); |
151 | /* atvauddemod_init(); */ |
152 | } |
153 | |
154 | if (err_code) { |
155 | pr_dbg("%s: init atvdemod error %d.\n", __func__, err_code); |
156 | return -1; |
157 | } |
158 | |
159 | /* aml_afc_timer_enable(fe); */ |
160 | /* aml_demod_timer_enable(fe); */ |
161 | |
162 | amlatvdemod_devp->std = 0; |
163 | amlatvdemod_devp->audmode = 0; |
164 | amlatvdemod_devp->soundsys = 0xFF; |
165 | |
166 | pr_info("%s: OK.\n", __func__); |
167 | |
168 | return 0; |
169 | } |
170 | |
171 | int atv_demod_leave_mode(struct dvb_frontend *fe) |
172 | { |
173 | struct atv_demod_priv *priv = fe->analog_demod_priv; |
174 | |
175 | priv->state = ATVDEMOD_STATE_IDEL; |
176 | priv->standby = true; |
177 | |
178 | usleep_range(30 * 1000, 30 * 1000 + 100); |
179 | |
180 | if (priv->afc.disable) |
181 | priv->afc.disable(&priv->afc); |
182 | |
183 | if (priv->monitor.disable) |
184 | priv->monitor.disable(&priv->monitor); |
185 | |
186 | atvdemod_uninit(); |
187 | if (!IS_ERR_OR_NULL(amlatvdemod_devp->agc_pin)) { |
188 | devm_pinctrl_put(amlatvdemod_devp->agc_pin); |
189 | amlatvdemod_devp->agc_pin = NULL; |
190 | } |
191 | |
192 | vdac_enable(0, 1); |
193 | adc_set_pll_cntl(0, ADC_EN_ATV_DEMOD, NULL); |
194 | if (is_meson_txlx_cpu() || is_meson_txhd_cpu() || is_meson_tl1_cpu()) |
195 | aud_demod_clk_gate(0); |
196 | |
197 | amlatvdemod_devp->std = 0; |
198 | amlatvdemod_devp->audmode = 0; |
199 | amlatvdemod_devp->soundsys = 0xFF; |
200 | |
201 | pr_info("%s: OK.\n", __func__); |
202 | |
203 | return 0; |
204 | } |
205 | |
206 | static void atv_demod_set_params(struct dvb_frontend *fe, |
207 | struct analog_parameters *params) |
208 | { |
209 | int ret = -1; |
210 | u32 if_info[2] = { 0 }; |
211 | struct atv_demod_priv *priv = fe->analog_demod_priv; |
212 | struct aml_atvdemod_parameters *p = &priv->atvdemod_param; |
213 | bool reconfig = false; |
214 | |
215 | priv->standby = true; |
216 | |
217 | /* afc tune disable,must cancel wq before set tuner freq*/ |
218 | if (priv->afc.disable) |
219 | priv->afc.disable(&priv->afc); |
220 | |
221 | if (priv->monitor.disable) |
222 | priv->monitor.disable(&priv->monitor); |
223 | |
224 | if (fe->ops.tuner_ops.set_analog_params) |
225 | ret = fe->ops.tuner_ops.set_analog_params(fe, params); |
226 | |
227 | if (fe->ops.tuner_ops.get_if_frequency) |
228 | ret = fe->ops.tuner_ops.get_if_frequency(fe, if_info); |
229 | |
230 | p->param.frequency = params->frequency; |
231 | p->param.mode = params->mode; |
232 | p->param.audmode = params->audmode; |
233 | p->param.std = params->std; |
234 | |
235 | p->if_inv = if_info[0]; |
236 | p->if_freq = if_info[1]; |
237 | |
238 | #if 0 /* unused */ |
239 | last_frq = p->param.frequency; |
240 | last_std = p->param.std; |
241 | #endif |
242 | |
243 | if ((p->tuner_id == AM_TUNER_R840) || |
244 | (p->tuner_id == AM_TUNER_R842) || |
245 | (p->tuner_id == AM_TUNER_SI2151) || |
246 | (p->tuner_id == AM_TUNER_SI2159) || |
247 | (p->tuner_id == AM_TUNER_MXL661)) |
248 | reconfig = false; |
249 | |
250 | /* In general, demod does not need to be reconfigured |
251 | * if parameters such as STD remain unchanged, |
252 | * but when the input signal frequency offset -0.25MHz, |
253 | * demod will be unlocked. That's very strange. |
254 | */ |
255 | if (reconfig || !priv->scanning || |
256 | amlatvdemod_devp->std != p->param.std || |
257 | amlatvdemod_devp->audmode != p->param.audmode || |
258 | amlatvdemod_devp->if_freq != p->if_freq || |
259 | amlatvdemod_devp->if_inv != p->if_inv || |
260 | amlatvdemod_devp->tuner_id != p->tuner_id) { |
261 | |
262 | amlatvdemod_devp->std = p->param.std; |
263 | amlatvdemod_devp->audmode = p->param.audmode; |
264 | amlatvdemod_devp->if_freq = p->if_freq; |
265 | amlatvdemod_devp->if_inv = p->if_inv; |
266 | amlatvdemod_devp->tuner_id = p->tuner_id; |
267 | |
268 | atv_dmd_set_std(); |
269 | atvdemod_init(!priv->scanning); |
270 | } else |
271 | atv_dmd_soft_reset(); |
272 | |
273 | if (!priv->scanning) |
274 | atvauddemod_init(); |
275 | |
276 | /* afc tune enable */ |
277 | /* analog_search_flag == 0 or afc_range != 0 means searching */ |
278 | if ((fe->ops.info.type == FE_ANALOG) |
279 | && (priv->scanning == false) |
280 | && (p->param.mode == 0)) { |
281 | if (priv->afc.enable) |
282 | priv->afc.enable(&priv->afc); |
283 | |
284 | if (priv->monitor.enable) |
285 | priv->monitor.enable(&priv->monitor); |
286 | |
287 | /* for searching mute audio */ |
288 | priv->standby = false; |
289 | } |
290 | } |
291 | |
292 | static int atv_demod_has_signal(struct dvb_frontend *fe, u16 *signal) |
293 | { |
294 | int vpll_lock = 0; |
295 | int line_lock = 0; |
296 | |
297 | retrieve_vpll_carrier_lock(&vpll_lock); |
298 | |
299 | /* add line lock status for atv scan */ |
300 | retrieve_vpll_carrier_line_lock(&line_lock); |
301 | |
302 | if (vpll_lock == 0 && line_lock == 0) { |
303 | *signal = V4L2_HAS_LOCK; |
304 | pr_info("%s locked [vpll_lock: 0x%x, line_lock:0x%x]\n", |
305 | __func__, vpll_lock, line_lock); |
306 | } else { |
307 | *signal = V4L2_TIMEDOUT; |
308 | pr_dbg("%s unlocked [vpll_lock: 0x%x, line_lock:0x%x]\n", |
309 | __func__, vpll_lock, line_lock); |
310 | } |
311 | |
312 | return 0; |
313 | } |
314 | |
315 | static void atv_demod_standby(struct dvb_frontend *fe) |
316 | { |
317 | struct atv_demod_priv *priv = fe->analog_demod_priv; |
318 | |
319 | if (priv->state != ATVDEMOD_STATE_IDEL) { |
320 | atv_demod_leave_mode(fe); |
321 | priv->state = ATVDEMOD_STATE_SLEEP; |
322 | priv->standby = true; |
323 | } |
324 | |
325 | pr_info("%s: OK.\n", __func__); |
326 | } |
327 | |
328 | static void atv_demod_tuner_status(struct dvb_frontend *fe) |
329 | { |
330 | pr_info("%s.\n", __func__); |
331 | } |
332 | |
333 | static int atv_demod_get_afc(struct dvb_frontend *fe, s32 *afc) |
334 | { |
335 | *afc = retrieve_vpll_carrier_afc(); |
336 | |
337 | return 0; |
338 | } |
339 | |
340 | static void atv_demod_release(struct dvb_frontend *fe) |
341 | { |
342 | int instance = 0; |
343 | struct atv_demod_priv *priv = fe->analog_demod_priv; |
344 | |
345 | mutex_lock(&atv_demod_list_mutex); |
346 | |
347 | atv_demod_leave_mode(fe); |
348 | |
349 | if (priv) |
350 | instance = hybrid_tuner_release_state(priv); |
351 | |
352 | if (instance == 0) |
353 | fe->analog_demod_priv = NULL; |
354 | |
355 | mutex_unlock(&atv_demod_list_mutex); |
356 | |
357 | pr_info("%s: OK.\n", __func__); |
358 | } |
359 | |
360 | static int atv_demod_set_config(struct dvb_frontend *fe, void *priv_cfg) |
361 | { |
362 | int *state = (int *) priv_cfg; |
363 | struct atv_demod_priv *priv = fe->analog_demod_priv; |
364 | |
365 | if (!state) { |
366 | pr_err("%s: state == NULL.\n", __func__); |
367 | return -1; |
368 | } |
369 | |
370 | mutex_lock(&atv_demod_list_mutex); |
371 | |
372 | switch (*state) { |
373 | case AML_ATVDEMOD_INIT: |
374 | if (priv->state != ATVDEMOD_STATE_WORK) { |
375 | priv->standby = true; |
376 | if (fe->ops.tuner_ops.set_config) |
377 | fe->ops.tuner_ops.set_config(fe, NULL); |
378 | if (!atv_demod_enter_mode(fe)) |
379 | priv->state = ATVDEMOD_STATE_WORK; |
380 | } |
381 | break; |
382 | |
383 | case AML_ATVDEMOD_UNINIT: |
384 | if (priv->state != ATVDEMOD_STATE_IDEL) { |
385 | atv_demod_leave_mode(fe); |
386 | if (fe->ops.tuner_ops.release) |
387 | fe->ops.tuner_ops.release(fe); |
388 | } |
389 | break; |
390 | |
391 | case AML_ATVDEMOD_RESUME: |
392 | if (priv->state == ATVDEMOD_STATE_SLEEP) { |
393 | if (!atv_demod_enter_mode(fe)) { |
394 | priv->state = ATVDEMOD_STATE_WORK; |
395 | priv->standby = false; |
396 | } |
397 | } |
398 | break; |
399 | |
400 | case AML_ATVDEMOD_SCAN_MODE: |
401 | priv->scanning = true; |
402 | if (priv->afc.disable) |
403 | priv->afc.disable(&priv->afc); |
404 | |
405 | if (priv->monitor.disable) |
406 | priv->monitor.disable(&priv->monitor); |
407 | break; |
408 | |
409 | case AML_ATVDEMOD_UNSCAN_MODE: |
410 | priv->scanning = false; |
411 | /* No need to enable when exiting the scan, |
412 | * but enable when actually played. |
413 | */ |
414 | #if 0 |
415 | if (priv->afc.enable) |
416 | priv->afc.enable(&priv->afc); |
417 | |
418 | if (priv->monitor.enable) |
419 | priv->monitor.enable(&priv->monitor); |
420 | #endif |
421 | break; |
422 | } |
423 | |
424 | mutex_unlock(&atv_demod_list_mutex); |
425 | |
426 | return 0; |
427 | } |
428 | |
429 | static struct analog_demod_ops atvdemod_ops = { |
430 | .info = { |
431 | .name = DEVICE_NAME, |
432 | }, |
433 | .set_params = atv_demod_set_params, |
434 | .has_signal = atv_demod_has_signal, |
435 | .standby = atv_demod_standby, |
436 | .tuner_status = atv_demod_tuner_status, |
437 | .get_afc = atv_demod_get_afc, |
438 | .release = atv_demod_release, |
439 | .set_config = atv_demod_set_config, |
440 | .i2c_gate_ctrl = NULL, |
441 | }; |
442 | |
443 | |
444 | unsigned int tuner_status_cnt = 4; /* 4-->16 test on sky mxl661 */ |
445 | |
446 | bool slow_mode; |
447 | |
448 | typedef int (*hook_func_t) (void); |
449 | hook_func_t aml_fe_hook_atv_status; |
450 | hook_func_t aml_fe_hook_hv_lock; |
451 | hook_func_t aml_fe_hook_get_fmt; |
452 | |
453 | void aml_fe_hook_cvd(hook_func_t atv_mode, hook_func_t cvd_hv_lock, |
454 | hook_func_t get_fmt) |
455 | { |
456 | aml_fe_hook_atv_status = atv_mode; |
457 | aml_fe_hook_hv_lock = cvd_hv_lock; |
458 | aml_fe_hook_get_fmt = get_fmt; |
459 | |
460 | pr_info("%s: OK.\n", __func__); |
461 | } |
462 | EXPORT_SYMBOL(aml_fe_hook_cvd); |
463 | |
464 | static v4l2_std_id atvdemod_fmt_2_v4l2_std(int fmt) |
465 | { |
466 | v4l2_std_id std = 0; |
467 | |
468 | switch (fmt) { |
469 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK: |
470 | std = V4L2_STD_PAL_DK; |
471 | break; |
472 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_I: |
473 | std = V4L2_STD_PAL_I; |
474 | break; |
475 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_BG: |
476 | std = V4L2_STD_PAL_BG; |
477 | break; |
478 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_M: |
479 | std = V4L2_STD_PAL_M; |
480 | break; |
481 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_DK: |
482 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_I: |
483 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_BG: |
484 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC: |
485 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC_M: |
486 | std = V4L2_STD_NTSC_M; |
487 | break; |
488 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_L: |
489 | std = V4L2_STD_SECAM_L; |
490 | break; |
491 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_DK2: |
492 | case AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_DK3: |
493 | std = V4L2_STD_SECAM_DK; |
494 | break; |
495 | default: |
496 | pr_err("%s: Unsupport fmt: 0x%0x.\n", __func__, fmt); |
497 | } |
498 | |
499 | return std; |
500 | } |
501 | |
502 | static v4l2_std_id atvdemod_fe_tvin_fmt_to_v4l2_std(int fmt) |
503 | { |
504 | v4l2_std_id std = 0; |
505 | |
506 | switch (fmt) { |
507 | case TVIN_SIG_FMT_CVBS_NTSC_M: |
508 | std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M; |
509 | break; |
510 | case TVIN_SIG_FMT_CVBS_NTSC_443: |
511 | std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_443; |
512 | break; |
513 | case TVIN_SIG_FMT_CVBS_NTSC_50: |
514 | std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M; |
515 | break; |
516 | case TVIN_SIG_FMT_CVBS_PAL_I: |
517 | std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_I; |
518 | break; |
519 | case TVIN_SIG_FMT_CVBS_PAL_M: |
520 | std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_M; |
521 | break; |
522 | case TVIN_SIG_FMT_CVBS_PAL_60: |
523 | std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_60; |
524 | break; |
525 | case TVIN_SIG_FMT_CVBS_PAL_CN: |
526 | std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_Nc; |
527 | break; |
528 | case TVIN_SIG_FMT_CVBS_SECAM: |
529 | std = V4L2_COLOR_STD_SECAM | V4L2_STD_SECAM_L; |
530 | break; |
531 | default: |
532 | pr_err("%s: Unsupport fmt: 0x%x\n", __func__, fmt); |
533 | break; |
534 | } |
535 | |
536 | return std; |
537 | } |
538 | |
539 | static void atvdemod_fe_try_analog_format(struct v4l2_frontend *v4l2_fe, |
540 | int auto_search_std, v4l2_std_id *video_fmt, |
541 | unsigned int *audio_fmt, unsigned int *soundsys) |
542 | { |
543 | struct dvb_frontend *fe = &v4l2_fe->fe; |
544 | struct v4l2_analog_parameters *p = &v4l2_fe->params; |
545 | struct analog_parameters params; |
546 | int i = 0; |
547 | int try_vfmt_cnt = 300; |
548 | int varify_cnt = 0; |
549 | int cvbs_std = 0; |
550 | v4l2_std_id std_bk = 0; |
551 | unsigned int broad_std = 0; |
552 | unsigned int audio = 0; |
553 | |
554 | if (auto_search_std & 0x01) { |
555 | for (i = 0; i < try_vfmt_cnt; i++) { |
556 | if (aml_fe_hook_get_fmt == NULL) { |
557 | pr_err("%s: aml_fe_hook_get_fmt == NULL.\n", |
558 | __func__); |
559 | break; |
560 | } |
561 | cvbs_std = aml_fe_hook_get_fmt(); |
562 | if (cvbs_std) { |
563 | varify_cnt++; |
564 | pr_dbg("get cvbs_std varify_cnt:%d, cnt:%d, cvbs_std:0x%x\n", |
565 | varify_cnt, i, |
566 | (unsigned int) cvbs_std); |
567 | if (((v4l2_fe->tuner_id == AM_TUNER_R840 |
568 | || v4l2_fe->tuner_id == AM_TUNER_R842) |
569 | && varify_cnt > 0) |
570 | || varify_cnt > 3) |
571 | break; |
572 | } |
573 | |
574 | if (i == (try_vfmt_cnt / 3) || |
575 | (i == (try_vfmt_cnt / 3) * 2)) { |
576 | /* Before enter search, |
577 | * need set the std, |
578 | * then, try others std. |
579 | */ |
580 | if (p->std & V4L2_COLOR_STD_PAL) |
581 | p->std = V4L2_COLOR_STD_NTSC |
582 | | V4L2_STD_NTSC_M; |
583 | #if 0 /*for secam */ |
584 | else if (p->std & V4L2_COLOR_STD_NTSC) |
585 | p->std = V4L2_COLOR_STD_SECAM |
586 | | V4L2_STD_SECAM; |
587 | #endif |
588 | else if (p->std & V4L2_COLOR_STD_NTSC) |
589 | p->std = V4L2_COLOR_STD_PAL |
590 | | V4L2_STD_PAL_DK; |
591 | |
592 | p->frequency += 1; |
593 | params.frequency = p->frequency; |
594 | params.mode = p->afc_range; |
595 | params.audmode = p->audmode; |
596 | params.std = p->std; |
597 | |
598 | fe->ops.analog_ops.set_params(fe, ¶ms); |
599 | } |
600 | usleep_range(30 * 1000, 30 * 1000 + 100); |
601 | } |
602 | |
603 | pr_dbg("get cvbs_std cnt:%d, cvbs_std: 0x%x\n", |
604 | i, (unsigned int) cvbs_std); |
605 | |
606 | if (cvbs_std == 0) { |
607 | pr_err("%s: failed to get video fmt, assume PAL.\n", |
608 | __func__); |
609 | cvbs_std = TVIN_SIG_FMT_CVBS_PAL_I; |
610 | p->std = V4L2_COLOR_STD_PAL | V4L2_STD_PAL_DK; |
611 | p->frequency += 1; |
612 | p->audmode = V4L2_STD_PAL_DK; |
613 | |
614 | params.frequency = p->frequency; |
615 | params.mode = p->afc_range; |
616 | params.audmode = p->audmode; |
617 | params.std = p->std; |
618 | |
619 | fe->ops.analog_ops.set_params(fe, ¶ms); |
620 | |
621 | usleep_range(20 * 1000, 20 * 1000 + 100); |
622 | } |
623 | |
624 | std_bk = atvdemod_fe_tvin_fmt_to_v4l2_std(cvbs_std); |
625 | } else { |
626 | /* Only search std by user setting, |
627 | * so no need tvafe identify signal. |
628 | */ |
629 | std_bk = p->std; |
630 | } |
631 | |
632 | *video_fmt = std_bk; |
633 | |
634 | if (!(auto_search_std & 0x02)) { |
635 | *audio_fmt = p->audmode; |
636 | return; |
637 | } |
638 | |
639 | if (std_bk & V4L2_COLOR_STD_NTSC) { |
640 | #if 1 /* For TV Signal Generator(TG39) test, NTSC need support other audio.*/ |
641 | if (cvbs_std == TVIN_SIG_FMT_CVBS_NTSC_M) { |
642 | broad_std = AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_M; |
643 | audio = V4L2_STD_NTSC_M; |
644 | } else { |
645 | amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_NTSC); |
646 | broad_std = aml_audiomode_autodet(v4l2_fe); |
647 | audio = atvdemod_fmt_2_v4l2_std(broad_std); |
648 | } |
649 | #if 0 /* I don't know what's going on here */ |
650 | if (audio == V4L2_STD_PAL_M) |
651 | audio = V4L2_STD_NTSC_M; |
652 | else |
653 | std_bk = V4L2_COLOR_STD_PAL; |
654 | #endif |
655 | #else /* Now, force to NTSC_M, Ours demod only support M for NTSC.*/ |
656 | audio = V4L2_STD_NTSC_M; |
657 | #endif |
658 | } else if (std_bk & V4L2_COLOR_STD_SECAM) { |
659 | #if 1 /* For support SECAM-DK/BG/I/L */ |
660 | amlatvdemod_set_std(AML_ATV_DEMOD_VIDEO_MODE_PROP_SECAM_L); |
661 | broad_std = aml_audiomode_autodet(v4l2_fe); |
662 | audio = atvdemod_fmt_2_v4l2_std(broad_std); |
663 | #else /* For force L */ |
664 | audio = V4L2_STD_SECAM_L; |
665 | #endif |
666 | } else { |
667 | /* V4L2_COLOR_STD_PAL */ |
668 | if (cvbs_std == TVIN_SIG_FMT_CVBS_PAL_M || |
669 | cvbs_std == TVIN_SIG_FMT_CVBS_PAL_CN) { |
670 | broad_std = AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_M; |
671 | audio = V4L2_STD_PAL_M; |
672 | } else { |
673 | amlatvdemod_set_std( |
674 | AML_ATV_DEMOD_VIDEO_MODE_PROP_PAL_DK); |
675 | broad_std = aml_audiomode_autodet(v4l2_fe); |
676 | audio = atvdemod_fmt_2_v4l2_std(broad_std); |
677 | } |
678 | #if 0 /* Why do this to me? We need support PAL_M.*/ |
679 | if (audio == V4L2_STD_PAL_M) { |
680 | audio = atvdemod_fmt_2_v4l2_std(broad_std_except_pal_m); |
681 | pr_info("select audmode 0x%x\n", audio); |
682 | } |
683 | #endif |
684 | } |
685 | |
686 | *audio_fmt = audio; |
687 | |
688 | /* for audio standard detection */ |
689 | if (is_meson_txlx_cpu() || is_meson_txhd_cpu() || is_meson_tl1_cpu()) { |
690 | *soundsys = amlfmt_aud_standard(broad_std); |
691 | *soundsys = (*soundsys << 16) | 0x00FFFF; |
692 | } else |
693 | *soundsys = 0xFFFFFF; |
694 | |
695 | pr_info("autodet audio broad_std %d, [%s][0x%x] soundsys[0x%x]\n", |
696 | broad_std, v4l2_std_to_str(audio), audio, *soundsys); |
697 | } |
698 | |
699 | static int atvdemod_fe_afc_closer(struct v4l2_frontend *v4l2_fe, int minafcfreq, |
700 | int maxafcfreq, int isAutoSearch) |
701 | { |
702 | struct dvb_frontend *fe = &v4l2_fe->fe; |
703 | struct v4l2_analog_parameters *p = &v4l2_fe->params; |
704 | struct analog_parameters params; |
705 | int afc = 100; |
706 | __u32 set_freq; |
707 | int count = 25; |
708 | int lock_cnt = 0; |
709 | static int freq_success; |
710 | static int temp_freq, temp_afc; |
711 | struct timespec time_now; |
712 | static struct timespec success_time; |
713 | unsigned int tuner_id = v4l2_fe->tuner_id; |
714 | |
715 | pr_dbg("[%s] freq_success: %d, freq: %d, minfreq: %d, maxfreq: %d\n", |
716 | __func__, freq_success, p->frequency, minafcfreq, maxafcfreq); |
717 | |
718 | /* avoid more search the same program, except < 45.00Mhz */ |
719 | if (abs(p->frequency - freq_success) < 3000000 |
720 | && p->frequency > 45000000) { |
721 | ktime_get_ts(&time_now); |
722 | pr_err("[%s] tv_sec now:%ld,tv_sec success:%ld\n", |
723 | __func__, time_now.tv_sec, success_time.tv_sec); |
724 | /* beyond 10s search same frequency is ok */ |
725 | if ((time_now.tv_sec - success_time.tv_sec) < 10) |
726 | return -1; |
727 | } |
728 | |
729 | /*do the auto afc make sure the afc < 50k or the range from api */ |
730 | if ((fe->ops.analog_ops.get_afc || fe->ops.tuner_ops.get_afc) && |
731 | fe->ops.tuner_ops.set_analog_params) { |
732 | |
733 | set_freq = p->frequency; |
734 | while (abs(afc) > AFC_BEST_LOCK) { |
735 | if (tuner_id == AM_TUNER_SI2151 || |
736 | tuner_id == AM_TUNER_SI2159 || |
737 | tuner_id == AM_TUNER_R840 || |
738 | tuner_id == AM_TUNER_R842) |
739 | usleep_range(10 * 1000, 10 * 1000 + 100); |
740 | else if (tuner_id == AM_TUNER_MXL661) |
741 | usleep_range(30 * 1000, 30 * 1000 + 100); |
742 | |
743 | if (fe->ops.analog_ops.get_afc && |
744 | ((tuner_id == AM_TUNER_R840) || |
745 | (tuner_id == AM_TUNER_R842) || |
746 | (tuner_id == AM_TUNER_SI2151) || |
747 | (tuner_id == AM_TUNER_SI2159) || |
748 | (tuner_id == AM_TUNER_MXL661))) |
749 | fe->ops.analog_ops.get_afc(fe, &afc); |
750 | else if (fe->ops.tuner_ops.get_afc) |
751 | fe->ops.tuner_ops.get_afc(fe, &afc); |
752 | |
753 | pr_dbg("[%s] get afc %d khz, freq %u.\n", |
754 | __func__, afc, p->frequency); |
755 | |
756 | if (afc == 0xffff) { |
757 | /*last lock, but this unlock,so try get afc*/ |
758 | if (lock_cnt > 0) { |
759 | p->frequency = temp_freq + |
760 | temp_afc * 1000; |
761 | pr_err("[%s] force lock, f:%d\n", |
762 | __func__, p->frequency); |
763 | break; |
764 | } |
765 | |
766 | afc = 500; |
767 | } else { |
768 | lock_cnt++; |
769 | temp_freq = p->frequency; |
770 | if (afc > 50) |
771 | temp_afc = 500; |
772 | else if (afc < -50) |
773 | temp_afc = -500; |
774 | else |
775 | temp_afc = afc; |
776 | } |
777 | |
778 | if (((abs(afc) > (500 - AFC_BEST_LOCK)) |
779 | && (abs(afc) < (500 + AFC_BEST_LOCK)) |
780 | && (abs(afc) != 500)) |
781 | || ((abs(afc) == 500) && (lock_cnt > 0))) { |
782 | p->frequency += afc * 1000; |
783 | break; |
784 | } |
785 | |
786 | if (afc >= (500 + AFC_BEST_LOCK)) |
787 | afc = 500; |
788 | |
789 | p->frequency += afc * 1000; |
790 | |
791 | if (unlikely(p->frequency > maxafcfreq)) { |
792 | pr_err("[%s] [%d] is exceed maxafcfreq[%d]\n", |
793 | __func__, p->frequency, maxafcfreq); |
794 | p->frequency = set_freq; |
795 | return -1; |
796 | } |
797 | #if 0 /*if enable, it would miss program*/ |
798 | if (unlikely(c->frequency < minafcfreq)) { |
799 | pr_dbg("[%s] [%d] is exceed minafcfreq[%d]\n", |
800 | __func__, |
801 | c->frequency, minafcfreq); |
802 | c->frequency = set_freq; |
803 | return -1; |
804 | } |
805 | #endif |
806 | if (likely(!(count--))) { |
807 | pr_err("[%s] exceed the afc count\n", __func__); |
808 | p->frequency = set_freq; |
809 | return -1; |
810 | } |
811 | |
812 | /* delete it will miss program |
813 | * when c->frequency equal program frequency |
814 | */ |
815 | p->frequency++; |
816 | if (fe->ops.tuner_ops.set_analog_params) { |
817 | params.frequency = p->frequency; |
818 | params.mode = p->afc_range; |
819 | params.audmode = p->audmode; |
820 | params.std = p->std; |
821 | fe->ops.tuner_ops.set_analog_params(fe, |
822 | ¶ms); |
823 | } |
824 | } |
825 | |
826 | /* After correcting the frequency offset success, |
827 | * need to set up tuner. |
828 | */ |
829 | if (fe->ops.tuner_ops.set_analog_params) { |
830 | params.frequency = p->frequency; |
831 | params.mode = p->afc_range; |
832 | params.audmode = p->audmode; |
833 | params.std = p->std; |
834 | fe->ops.tuner_ops.set_analog_params(fe, |
835 | ¶ms); |
836 | |
837 | if (tuner_id == AM_TUNER_SI2151 || |
838 | tuner_id == AM_TUNER_SI2159 || |
839 | tuner_id == AM_TUNER_R840 || |
840 | tuner_id == AM_TUNER_R842) |
841 | usleep_range(10 * 1000, 10 * 1000 + 100); |
842 | else if (tuner_id == AM_TUNER_MXL661) |
843 | usleep_range(30 * 1000, 30 * 1000 + 100); |
844 | } |
845 | |
846 | freq_success = p->frequency; |
847 | ktime_get_ts(&success_time); |
848 | pr_dbg("[%s] get afc %d khz done, freq %u.\n", |
849 | __func__, afc, p->frequency); |
850 | } |
851 | |
852 | return 0; |
853 | } |
854 | |
855 | static int atvdemod_fe_set_property(struct v4l2_frontend *v4l2_fe, |
856 | struct v4l2_property *tvp) |
857 | { |
858 | struct dvb_frontend *fe = &v4l2_fe->fe; |
859 | struct atv_demod_priv *priv = fe->analog_demod_priv; |
860 | struct v4l2_analog_parameters *params = &v4l2_fe->params; |
861 | |
862 | pr_dbg("%s: cmd = 0x%x.\n", __func__, tvp->cmd); |
863 | |
864 | switch (tvp->cmd) { |
865 | case V4L2_SOUND_SYS: |
866 | /* aud_mode = tvp->data & 0xFF; */ |
867 | amlatvdemod_devp->soundsys = tvp->data & 0xFF; |
868 | if (amlatvdemod_devp->soundsys != 0xFF) { |
869 | aud_mode = amlatvdemod_devp->soundsys; |
870 | params->soundsys = aud_mode; |
871 | } |
872 | priv->sound_sys.output_mode = tvp->data & 0xFF; |
873 | break; |
874 | |
875 | case V4L2_SLOW_SEARCH_MODE: |
876 | tvp->data = slow_mode; |
877 | break; |
878 | |
879 | default: |
880 | pr_dbg("%s: property %d doesn't exist\n", |
881 | __func__, tvp->cmd); |
882 | return -EINVAL; |
883 | } |
884 | |
885 | return 0; |
886 | } |
887 | |
888 | static int atvdemod_fe_get_property(struct v4l2_frontend *v4l2_fe, |
889 | struct v4l2_property *tvp) |
890 | { |
891 | pr_dbg("%s: cmd = 0x%x.\n", __func__, tvp->cmd); |
892 | |
893 | switch (tvp->cmd) { |
894 | case V4L2_SOUND_SYS: |
895 | tvp->data = ((aud_std & 0xFF) << 16) |
896 | | ((signal_audmode & 0xFF) << 8) |
897 | | (aud_mode & 0xFF); |
898 | break; |
899 | |
900 | case V4L2_SLOW_SEARCH_MODE: |
901 | slow_mode = tvp->data; |
902 | break; |
903 | |
904 | default: |
905 | pr_dbg("%s: property %d doesn't exist\n", |
906 | __func__, tvp->cmd); |
907 | return -EINVAL; |
908 | } |
909 | |
910 | return 0; |
911 | } |
912 | |
913 | static enum v4l2_search atvdemod_fe_search(struct v4l2_frontend *v4l2_fe) |
914 | { |
915 | struct analog_parameters params; |
916 | struct dvb_frontend *fe = &v4l2_fe->fe; |
917 | struct atv_demod_priv *priv = NULL; |
918 | struct v4l2_analog_parameters *p = &v4l2_fe->params; |
919 | enum v4l2_status tuner_state = V4L2_TIMEDOUT; |
920 | enum v4l2_status ade_state = V4L2_TIMEDOUT; |
921 | bool pll_lock = false; |
922 | /*struct atv_status_s atv_status;*/ |
923 | __u32 set_freq = 0; |
924 | __u32 minafcfreq = 0, maxafcfreq = 0; |
925 | __u32 afc_step = 0; |
926 | int tuner_status_cnt_local = tuner_status_cnt; |
927 | v4l2_std_id std_bk = 0; |
928 | unsigned int audio = 0; |
929 | unsigned int soundsys = 0; |
930 | int double_check_cnt = 1; |
931 | int auto_search_std = 0; |
932 | int search_count = 0; |
933 | /* bool try_secam = false; */ |
934 | int ret = -1; |
935 | unsigned int tuner_id = v4l2_fe->tuner_id; |
936 | int priv_cfg = 0; |
937 | |
938 | if (unlikely(!fe || !p || |
939 | !fe->ops.tuner_ops.get_status || |
940 | !fe->ops.analog_ops.has_signal || |
941 | !fe->ops.analog_ops.set_params || |
942 | !fe->ops.analog_ops.set_config)) { |
943 | pr_err("[%s] error: NULL function or pointer.\n", __func__); |
944 | return V4L2_SEARCH_INVALID; |
945 | } |
946 | |
947 | priv = fe->analog_demod_priv; |
948 | if (priv->state != ATVDEMOD_STATE_WORK) { |
949 | pr_err("[%s] ATV state is not work.\n", __func__); |
950 | return V4L2_SEARCH_INVALID; |
951 | } |
952 | |
953 | if (p->afc_range == 0) { |
954 | pr_err("[%s] afc_range == 0, skip the search\n", __func__); |
955 | return V4L2_SEARCH_INVALID; |
956 | } |
957 | |
958 | pr_info("[%s] afc_range: [%d], tuner: [%d], freq: [%d], flag: [%d].\n", |
959 | __func__, p->afc_range, tuner_id, |
960 | p->frequency, p->flag); |
961 | |
962 | /* backup the freq by api */ |
963 | set_freq = p->frequency; |
964 | |
965 | /* Before enter search, need set the std first. |
966 | * If set p->analog.std == 0, will search all std (PAL/NTSC/SECAM), |
967 | * and need tvafe identify signal type. |
968 | */ |
969 | if (p->std == 0) { |
970 | p->std = V4L2_COLOR_STD_NTSC | V4L2_STD_NTSC_M; |
971 | /* p->std = V4L2_COLOR_STD_PAL | V4L2_STD_DK; */ |
972 | auto_search_std = 0x01; |
973 | pr_dbg("[%s] user std is 0, so set it to NTSC | M.\n", |
974 | __func__); |
975 | } |
976 | |
977 | if (p->audmode == 0) { |
978 | if (auto_search_std) |
979 | p->audmode = p->std & 0x00FFFFFF; |
980 | else { |
981 | if (p->std & V4L2_COLOR_STD_PAL) |
982 | p->audmode = V4L2_STD_PAL_DK; |
983 | else if (p->std & V4L2_COLOR_STD_NTSC) |
984 | p->audmode = V4L2_STD_NTSC_M; |
985 | else if (p->std & V4L2_COLOR_STD_SECAM) |
986 | p->audmode = V4L2_STD_PAL_DK; |
987 | |
988 | p->std = (p->std & 0xFF000000) | p->audmode; |
989 | } |
990 | auto_search_std |= 0x02; |
991 | pr_dbg("[%s] user audmode is 0, so set it to %s.\n", |
992 | __func__, v4l2_std_to_str(p->audmode)); |
993 | } |
994 | |
995 | priv_cfg = AML_ATVDEMOD_SCAN_MODE; |
996 | fe->ops.analog_ops.set_config(fe, &priv_cfg); |
997 | |
998 | /*set the afc_range and start freq*/ |
999 | minafcfreq = p->frequency - p->afc_range; |
1000 | maxafcfreq = p->frequency + p->afc_range; |
1001 | |
1002 | /*from the current freq start, and set the afc_step*/ |
1003 | /*if step is 2Mhz,r840 will miss program*/ |
1004 | if (slow_mode || |
1005 | (tuner_id == AM_TUNER_R840 || tuner_id == AM_TUNER_R842) || |
1006 | (p->afc_range == ATV_AFC_1_0MHZ)) { |
1007 | pr_dbg("[%s] slow mode to search the channel\n", __func__); |
1008 | afc_step = ATV_AFC_1_0MHZ; |
1009 | } else if (!slow_mode) { |
1010 | afc_step = p->afc_range/* ATV_AFC_2_0MHZ */; |
1011 | } else { |
1012 | pr_dbg("[%s] slow mode to search the channel\n", __func__); |
1013 | afc_step = ATV_AFC_1_0MHZ; |
1014 | } |
1015 | |
1016 | /**enter auto search mode**/ |
1017 | pr_dbg("[%s] Auto search std: 0x%08x, audmode: 0x%08x\n", |
1018 | __func__, (unsigned int) p->std, p->audmode); |
1019 | |
1020 | while (minafcfreq <= p->frequency && |
1021 | p->frequency <= maxafcfreq) { |
1022 | |
1023 | params.frequency = p->frequency; |
1024 | params.mode = p->afc_range; |
1025 | params.audmode = p->audmode; |
1026 | params.std = p->std; |
1027 | fe->ops.analog_ops.set_params(fe, ¶ms); |
1028 | |
1029 | pr_dbg("[%s] [%d] is processing, [min=%d, max=%d].\n", |
1030 | __func__, p->frequency, minafcfreq, maxafcfreq); |
1031 | |
1032 | pll_lock = false; |
1033 | tuner_status_cnt_local = tuner_status_cnt; |
1034 | do { |
1035 | if (tuner_id == AM_TUNER_MXL661) { |
1036 | usleep_range(30 * 1000, 30 * 1000 + 100); |
1037 | } else if (tuner_id == AM_TUNER_R840 || |
1038 | tuner_id == AM_TUNER_R842) { |
1039 | usleep_range(10 * 1000, 10 * 1000 + 100); |
1040 | fe->ops.tuner_ops.get_status(fe, |
1041 | (u32 *)&tuner_state); |
1042 | } else { |
1043 | /* AM_TUNER_SI2151 and AM_TUNER_SI2159 */ |
1044 | usleep_range(10 * 1000, 10 * 1000 + 100); |
1045 | } |
1046 | |
1047 | fe->ops.analog_ops.has_signal(fe, (u16 *)&ade_state); |
1048 | tuner_status_cnt_local--; |
1049 | if (((ade_state == V4L2_HAS_LOCK || |
1050 | tuner_state == V4L2_HAS_LOCK) && |
1051 | (tuner_id != AM_TUNER_R840 && |
1052 | tuner_id != AM_TUNER_R842)) || |
1053 | ((ade_state == V4L2_HAS_LOCK && |
1054 | tuner_state == V4L2_HAS_LOCK) && |
1055 | (tuner_id == AM_TUNER_R840 || |
1056 | tuner_id == AM_TUNER_R842))) { |
1057 | pll_lock = true; |
1058 | break; |
1059 | } |
1060 | |
1061 | if (tuner_status_cnt_local == 0) { |
1062 | #if 0 /* when need to support secam-l, will enable it */ |
1063 | if (auto_search_std && |
1064 | try_secam == false && |
1065 | !(p->std & V4L2_COLOR_STD_SECAM) && |
1066 | !(p->std & V4L2_STD_SECAM_L)) { |
1067 | /* backup the std and audio mode */ |
1068 | std_bk = p->std; |
1069 | audio = p->audmode; |
1070 | |
1071 | p->std = (V4L2_COLOR_STD_SECAM |
1072 | | V4L2_STD_SECAM_L); |
1073 | p->audmode = V4L2_STD_SECAM_L; |
1074 | |
1075 | params.frequency = p->frequency; |
1076 | params.mode = p->afc_range; |
1077 | params.audmode = p->audmode; |
1078 | params.std = p->std; |
1079 | fe->ops.analog_ops.set_params(fe, |
1080 | ¶ms); |
1081 | |
1082 | try_secam = true; |
1083 | |
1084 | tuner_status_cnt_local = |
1085 | tuner_status_cnt / 2; |
1086 | |
1087 | continue; |
1088 | } |
1089 | |
1090 | if (try_secam) { |
1091 | p->std = std_bk; |
1092 | p->audmode = audio; |
1093 | |
1094 | params.frequency = p->frequency; |
1095 | params.mode = p->afc_range; |
1096 | params.audmode = p->audmode; |
1097 | params.std = p->std; |
1098 | fe->ops.analog_ops.set_params(fe, |
1099 | ¶ms); |
1100 | |
1101 | try_secam = false; |
1102 | } |
1103 | #endif |
1104 | break; |
1105 | } |
1106 | } while (1); |
1107 | |
1108 | std_bk = 0; |
1109 | audio = 0; |
1110 | |
1111 | if (pll_lock) { |
1112 | |
1113 | pr_dbg("[%s] freq: [%d] pll lock success\n", |
1114 | __func__, p->frequency); |
1115 | |
1116 | ret = atvdemod_fe_afc_closer(v4l2_fe, minafcfreq, |
1117 | maxafcfreq + ATV_AFC_500KHZ, 1); |
1118 | if (ret == 0) { |
1119 | atvdemod_fe_try_analog_format(v4l2_fe, |
1120 | auto_search_std, |
1121 | &std_bk, &audio, &soundsys); |
1122 | |
1123 | pr_info("[%s] freq:%d, std_bk:0x%x, audmode:0x%x, search OK.\n", |
1124 | __func__, p->frequency, |
1125 | (unsigned int) std_bk, audio); |
1126 | |
1127 | if (std_bk != 0) { |
1128 | p->audmode = audio; |
1129 | p->std = std_bk; |
1130 | /*avoid std unenable */ |
1131 | p->frequency -= 1; |
1132 | p->soundsys = soundsys; |
1133 | std_bk = 0; |
1134 | audio = 0; |
1135 | } |
1136 | |
1137 | /* sync param */ |
1138 | /* aml_fe_analog_sync_frontend(fe); */ |
1139 | priv_cfg = AML_ATVDEMOD_UNSCAN_MODE; |
1140 | fe->ops.analog_ops.set_config(fe, &priv_cfg); |
1141 | return V4L2_SEARCH_SUCCESS; |
1142 | } |
1143 | } |
1144 | |
1145 | pr_dbg("[%s] freq[analog.std:0x%08x] is[%d] unlock\n", |
1146 | __func__, |
1147 | (uint32_t) p->std, p->frequency); |
1148 | |
1149 | /* when manual search, just search current freq */ |
1150 | if (p->flag == ANALOG_FLAG_MANUL_SCAN) |
1151 | break; |
1152 | |
1153 | if (p->frequency >= 44200000 && |
1154 | p->frequency <= 44300000 && |
1155 | double_check_cnt) { |
1156 | double_check_cnt--; |
1157 | pr_err("%s 44.25Mhz double check\n", __func__); |
1158 | } else { |
1159 | ++search_count; |
1160 | p->frequency += afc_step * ((search_count % 2) ? |
1161 | -search_count : search_count); |
1162 | } |
1163 | } |
1164 | |
1165 | pr_dbg("[%s] [%d] over of range [min=%d, max=%d], search failed.\n", |
1166 | __func__, p->frequency, minafcfreq, maxafcfreq); |
1167 | p->frequency = set_freq; |
1168 | |
1169 | priv_cfg = AML_ATVDEMOD_UNSCAN_MODE; |
1170 | fe->ops.analog_ops.set_config(fe, &priv_cfg); |
1171 | |
1172 | return DVBFE_ALGO_SEARCH_FAILED; |
1173 | } |
1174 | |
1175 | static struct v4l2_frontend_ops atvdemod_fe_ops = { |
1176 | .set_property = atvdemod_fe_set_property, |
1177 | .get_property = atvdemod_fe_get_property, |
1178 | .search = atvdemod_fe_search, |
1179 | }; |
1180 | |
1181 | struct dvb_frontend *aml_atvdemod_attach(struct dvb_frontend *fe, |
1182 | struct v4l2_frontend *v4l2_fe, |
1183 | struct i2c_adapter *i2c_adap, u8 i2c_addr, u32 tuner_id) |
1184 | { |
1185 | int instance = 0; |
1186 | struct atv_demod_priv *priv = NULL; |
1187 | |
1188 | mutex_lock(&atv_demod_list_mutex); |
1189 | |
1190 | instance = hybrid_tuner_request_state(struct atv_demod_priv, priv, |
1191 | hybrid_tuner_instance_list, |
1192 | i2c_adap, i2c_addr, DEVICE_NAME); |
1193 | |
1194 | priv->atvdemod_param.tuner_id = tuner_id; |
1195 | |
1196 | switch (instance) { |
1197 | case 0: |
1198 | mutex_unlock(&atv_demod_list_mutex); |
1199 | return NULL; |
1200 | case 1: |
1201 | fe->analog_demod_priv = priv; |
1202 | |
1203 | priv->afc.fe = fe; |
1204 | atv_demod_afc_init(&priv->afc); |
1205 | |
1206 | priv->monitor.fe = fe; |
1207 | atv_demod_monitor_init(&priv->monitor); |
1208 | |
1209 | priv->standby = true; |
1210 | |
1211 | pr_info("%s: aml_atvdemod found.\n", __func__); |
1212 | break; |
1213 | default: |
1214 | fe->analog_demod_priv = priv; |
1215 | break; |
1216 | } |
1217 | |
1218 | mutex_unlock(&atv_demod_list_mutex); |
1219 | |
1220 | fe->ops.info.type = FE_ANALOG; |
1221 | |
1222 | memcpy(&fe->ops.analog_ops, &atvdemod_ops, |
1223 | sizeof(struct analog_demod_ops)); |
1224 | |
1225 | memcpy(&v4l2_fe->ops, &atvdemod_fe_ops, |
1226 | sizeof(struct v4l2_frontend_ops)); |
1227 | |
1228 | return fe; |
1229 | } |
1230 | EXPORT_SYMBOL(aml_atvdemod_attach); |
1231 |