blob: 964bc42c224eabe28bf823cf31dd1debff5aa2ca
1 | /* |
2 | * Silicon labs atvdemod Device Driver |
3 | * |
4 | * Author: dezhi.kong <dezhi.kong@amlogic.com> |
5 | * |
6 | * |
7 | * Copyright (C) 2014 Amlogic Inc. |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 as |
11 | * published by the Free Software Foundation. |
12 | */ |
13 | |
14 | /* Standard Liniux Headers */ |
15 | #include <linux/init.h> |
16 | #include <linux/kernel.h> |
17 | #include <linux/module.h> |
18 | #include <linux/i2c.h> |
19 | #include <linux/delay.h> |
20 | #include <linux/slab.h> |
21 | #include <linux/err.h> |
22 | #include <linux/delay.h> |
23 | #include <linux/jiffies.h> |
24 | #include <linux/platform_device.h> |
25 | #include <linux/io.h> |
26 | |
27 | /* Amlogic Headers */ |
28 | |
29 | /* Local Headers */ |
30 | #include "atvdemod_func.h" |
31 | #include "../aml_fe.h" |
32 | #include <uapi/linux/dvb/frontend.h> |
33 | #include <linux/amlogic/tvin/tvin.h> |
34 | |
35 | #define ATVDEMOD_DEVICE_NAME "amlatvdemod" |
36 | #define ATVDEMOD_DRIVER_NAME "amlatvdemod" |
37 | #define ATVDEMOD_MODULE_NAME "amlatvdemod" |
38 | #define ATVDEMOD_CLASS_NAME "amlatvdemod" |
39 | |
40 | struct amlatvdemod_device_s *amlatvdemod_devp; |
41 | #define AMLATVDEMOD_VER "Ref.2015/09/01a" |
42 | |
43 | static int afc_wave_cnt; |
44 | static int last_frq, last_std; |
45 | |
46 | unsigned int reg_23cf = 0x88188832; /*IIR filter*/ |
47 | module_param(reg_23cf, uint, 0664); |
48 | MODULE_PARM_DESC(reg_23cf, "\n reg_23cf\n"); |
49 | |
50 | unsigned int atvdemod_scan_mode; /*IIR filter*/ |
51 | module_param(atvdemod_scan_mode, uint, 0664); |
52 | MODULE_PARM_DESC(atvdemod_scan_mode, "\n atvdemod_scan_mode\n"); |
53 | |
54 | /* used for resume */ |
55 | #define ATVDEMOD_STATE_IDEL 0 |
56 | #define ATVDEMOD_STATE_WORK 1 |
57 | #define ATVDEMOD_STATE_SLEEP 2 |
58 | static int atvdemod_state = ATVDEMOD_STATE_IDEL; |
59 | |
60 | int is_atvdemod_scan_mode(void) |
61 | { |
62 | return atvdemod_scan_mode; |
63 | } |
64 | EXPORT_SYMBOL(is_atvdemod_scan_mode); |
65 | |
66 | static int aml_atvdemod_enter_mode(struct aml_fe *fe, int mode); |
67 | /*static void sound_store(const char *buff, v4l2_std_id *std);*/ |
68 | static ssize_t aml_atvdemod_store(struct class *cls, |
69 | struct class_attribute *attr, const char *buf, |
70 | size_t count) |
71 | { |
72 | int n = 0; |
73 | unsigned int ret = 0; |
74 | char *buf_orig, *ps, *token; |
75 | char *parm[4]; |
76 | unsigned int data_snr[128]; |
77 | unsigned int data_snr_avg; |
78 | int data_afc, block_addr, block_reg, block_val = 0; |
79 | int i, val = 0; |
80 | unsigned long tmp = 0; |
81 | struct aml_fe *atvdemod_fe = NULL; |
82 | |
83 | buf_orig = kstrdup(buf, GFP_KERNEL); |
84 | ps = buf_orig; |
85 | block_addr = 0; |
86 | block_reg = 0; |
87 | while (1) { |
88 | token = strsep(&ps, "\n"); |
89 | if (token == NULL) |
90 | break; |
91 | if (*token == '\0') |
92 | continue; |
93 | parm[n++] = token; |
94 | } |
95 | if (!strncmp(parm[0], "init", strlen("init"))) { |
96 | ret = aml_atvdemod_enter_mode(atvdemod_fe, 0); |
97 | if (ret) |
98 | pr_info("[tuner..] atv_restart error.\n"); |
99 | } else if (!strcmp(parm[0], "tune")) { |
100 | /* val = simple_strtol(parm[1], NULL, 10); */ |
101 | } else if (!strcmp(parm[0], "set")) { |
102 | if (!strncmp(parm[1], "avout_gain", strlen("avout_gain"))) { |
103 | if (kstrtoul(buf+strlen("avout_offset")+1, 10, |
104 | &tmp) == 0) |
105 | val = tmp; |
106 | atv_dmd_wr_byte(0x0c, 0x01, val&0xff); |
107 | } else if (!strncmp(parm[1], "avout_offset", |
108 | strlen("avout_offset"))) { |
109 | if (kstrtoul(buf+strlen("avout_offset")+1, 10, |
110 | &tmp) == 0) |
111 | val = tmp; |
112 | atv_dmd_wr_byte(0x0c, 0x04, val&0xff); |
113 | } else if (!strncmp(parm[1], "atv_gain", strlen("atv_gain"))) { |
114 | if (kstrtoul(buf+strlen("atv_gain")+1, 10, &tmp) == 0) |
115 | val = tmp; |
116 | atv_dmd_wr_byte(0x19, 0x01, val&0xff); |
117 | } else if (!strncmp(parm[1], "atv_offset", |
118 | strlen("atv_offset"))) { |
119 | if (kstrtoul(buf+strlen("atv_offset")+1, 10, |
120 | &tmp) == 0) |
121 | val = tmp; |
122 | atv_dmd_wr_byte(0x19, 0x04, val&0xff); |
123 | } |
124 | } else if (!strcmp(parm[0], "get")) { |
125 | if (!strncmp(parm[1], "avout_gain", strlen("avout_gain"))) { |
126 | val = atv_dmd_rd_byte(0x0c, 0x01); |
127 | pr_dbg("avout_gain:0x%x\n", val); |
128 | } else if (!strncmp(parm[1], "avout_offset", |
129 | strlen("avout_offset"))) { |
130 | val = atv_dmd_rd_byte(0x0c, 0x04); |
131 | pr_dbg("avout_offset:0x%x\n", val); |
132 | } else if (!strncmp(parm[1], "atv_gain", strlen("atv_gain"))) { |
133 | val = atv_dmd_rd_byte(0x19, 0x01); |
134 | pr_dbg("atv_gain:0x%x\n", val); |
135 | } else if (!strncmp(parm[1], "atv_offset", |
136 | strlen("atv_offset"))) { |
137 | val = atv_dmd_rd_byte(0x19, 0x04); |
138 | pr_dbg("atv_offset:0x%x\n", val); |
139 | } |
140 | } else if (!strncmp(parm[0], "snr_hist", strlen("snr_hist"))) { |
141 | data_snr_avg = 0; |
142 | for (i = 0; i < 128; i++) { |
143 | data_snr[i] = |
144 | (atv_dmd_rd_long(APB_BLOCK_ADDR_VDAGC, 0x50) >> 8); |
145 | usleep_range(50*1000, 50*1000+100); |
146 | data_snr_avg += data_snr[i]; |
147 | } |
148 | data_snr_avg = data_snr_avg / 128; |
149 | pr_dbg("**********snr_hist_128avg:0x%x(%d)*********\n", |
150 | data_snr_avg, data_snr_avg); |
151 | } else if (!strncmp(parm[0], "afc_info", strlen("afc_info"))) { |
152 | data_afc = retrieve_vpll_carrier_afc(); |
153 | pr_dbg("[amlatvdemod..]afc %d Khz.\n", data_afc); |
154 | } else if (!strncmp(parm[0], "ver_info", strlen("ver_info"))) { |
155 | pr_dbg("[amlatvdemod..]aml_atvdemod_ver %s.\n", |
156 | AMLATVDEMOD_VER); |
157 | } else if (!strncmp(parm[0], "audio_autodet", |
158 | strlen("audio_autodet"))) { |
159 | aml_audiomode_autodet(NULL); |
160 | } else if (!strncmp(parm[0], "overmodule_det", |
161 | strlen("overmodule_det"))) { |
162 | /* unsigned long over_threshold, */ |
163 | /* int det_mode = auto_det_mode; */ |
164 | aml_atvdemod_overmodule_det(); |
165 | } else if (!strncmp(parm[0], "audio_gain_set", |
166 | strlen("audio_gain_set"))) { |
167 | if (kstrtoul(buf+strlen("audio_gain_set")+1, 16, &tmp) == 0) |
168 | val = tmp; |
169 | aml_audio_valume_gain_set(val); |
170 | pr_dbg("audio_gain_set : %d\n", val); |
171 | } else if (!strncmp(parm[0], "audio_gain_get", |
172 | strlen("audio_gain_get"))) { |
173 | val = aml_audio_valume_gain_get(); |
174 | pr_dbg("audio_gain_get : %d\n", val); |
175 | } else if (!strncmp(parm[0], "fix_pwm_adj", strlen("fix_pwm_adj"))) { |
176 | if (kstrtoul(parm[1], 10, &tmp) == 0) { |
177 | val = tmp; |
178 | aml_fix_PWM_adjust(val); |
179 | } |
180 | } else if (!strncmp(parm[0], "rs", strlen("rs"))) { |
181 | if (kstrtoul(parm[1], 16, &tmp) == 0) |
182 | block_addr = tmp; |
183 | if (kstrtoul(parm[2], 16, &tmp) == 0) |
184 | block_reg = tmp; |
185 | if (block_addr < APB_BLOCK_ADDR_TOP) |
186 | block_val = atv_dmd_rd_long(block_addr, block_reg); |
187 | pr_info("rs block_addr:0x%x,block_reg:0x%x,block_val:0x%x\n", |
188 | block_addr, block_reg, block_val); |
189 | } else if (!strncmp(parm[0], "ws", strlen("ws"))) { |
190 | if (kstrtoul(parm[1], 16, &tmp) == 0) |
191 | block_addr = tmp; |
192 | if (kstrtoul(parm[2], 16, &tmp) == 0) |
193 | block_reg = tmp; |
194 | if (kstrtoul(parm[3], 16, &tmp) == 0) |
195 | block_val = tmp; |
196 | if (block_addr < APB_BLOCK_ADDR_TOP) |
197 | atv_dmd_wr_long(block_addr, block_reg, block_val); |
198 | pr_info("ws block_addr:0x%x,block_reg:0x%x,block_val:0x%x\n", |
199 | block_addr, block_reg, block_val); |
200 | block_val = atv_dmd_rd_long(block_addr, block_reg); |
201 | pr_info("readback_val:0x%x\n", block_val); |
202 | } else if (!strncmp(parm[0], "pin_mux", strlen("pin_mux"))) { |
203 | amlatvdemod_devp->pin = |
204 | devm_pinctrl_get_select(amlatvdemod_devp->dev, |
205 | amlatvdemod_devp->pin_name); |
206 | pr_dbg("atvdemod agc pinmux name:%s\n", |
207 | amlatvdemod_devp->pin_name); |
208 | } else if (!strncmp(parm[0], "snr_cur", strlen("snr_cur"))) { |
209 | data_snr_avg = aml_atvdemod_get_snr_ex(); |
210 | pr_dbg("**********snr_cur:%d*********\n", data_snr_avg); |
211 | } else |
212 | pr_dbg("invalid command\n"); |
213 | kfree(buf_orig); |
214 | return count; |
215 | } |
216 | |
217 | static ssize_t aml_atvdemod_show(struct class *cls, |
218 | struct class_attribute *attr, char *buff) |
219 | { |
220 | pr_dbg("\n usage:\n"); |
221 | pr_dbg("[get soft version] echo ver_info > /sys/class/amlatvdemod/atvdemod_debug\n"); |
222 | pr_dbg("[get afc value] echo afc_info > /sys/class/amlatvdemod/atvdemod_debug\n"); |
223 | pr_dbg("[reinit atvdemod] echo init > /sys/class/amlatvdemod/atvdemod_debug\n"); |
224 | pr_dbg("[get av-out-gain/av-out-offset/atv-gain/atv-offset]:\n" |
225 | "echo get av_gain/av_offset/atv_gain/atv_offset > /sys/class/amlatvdemod/atvdemod_debug\n"); |
226 | pr_dbg("[set av-out-gain/av-out-offset/atv-gain/atv-offset]:\n" |
227 | "echo set av_gain/av_offset/atv_gain/atv_offset val(0~255) > /sys/class/amlatvdemod/atvdemod_debug\n"); |
228 | return 0; |
229 | } |
230 | static CLASS_ATTR(atvdemod_debug, 0644, aml_atvdemod_show, aml_atvdemod_store); |
231 | |
232 | void aml_atvdemod_set_frequency(unsigned int freq) |
233 | { |
234 | } |
235 | |
236 | /*static void aml_atvdemod_set_std(void);*/ |
237 | |
238 | /*try audmode B,CH,I,DK,return the sound level*/ |
239 | /*static unsigned char set_video_audio_mode(unsigned char color, |
240 | *unsigned char audmode); |
241 | */ |
242 | /*static void aml_atvdemod_get_status(struct dvb_frontend *fe, |
243 | *void *stat); |
244 | */ |
245 | /*static void aaaml_atvdemod_get_pll_status(struct dvb_frontend *fe, |
246 | *void *stat); |
247 | */ |
248 | |
249 | static int aml_atvdemod_fe_init(struct aml_fe_dev *dev) |
250 | { |
251 | |
252 | int error_code = 0; |
253 | |
254 | if (!dev) { |
255 | pr_dbg("[amlatvdemod..]%s: null pointer error.\n", __func__); |
256 | return -1; |
257 | } |
258 | return error_code; |
259 | } |
260 | |
261 | static int aml_atvdemod_enter_mode(struct aml_fe *fe, int mode) |
262 | { |
263 | int err_code; |
264 | |
265 | if (amlatvdemod_devp->pin_name != NULL) |
266 | amlatvdemod_devp->pin = |
267 | devm_pinctrl_get_select(amlatvdemod_devp->dev, |
268 | amlatvdemod_devp->pin_name); |
269 | /* printk("\n%s: set atvdemod pll...\n",__func__); */ |
270 | adc_set_pll_cntl(1, 0x1); |
271 | atvdemod_clk_init(); |
272 | err_code = atvdemod_init(); |
273 | if (err_code) { |
274 | pr_dbg("[amlatvdemod..]%s init atvdemod error.\n", __func__); |
275 | return err_code; |
276 | } |
277 | |
278 | set_aft_thread_enable(1); |
279 | atvdemod_state = ATVDEMOD_STATE_WORK; |
280 | return 0; |
281 | } |
282 | |
283 | static int aml_atvdemod_leave_mode(struct aml_fe *fe, int mode) |
284 | { |
285 | set_aft_thread_enable(0); |
286 | atvdemod_uninit(); |
287 | if (amlatvdemod_devp->pin != NULL) { |
288 | devm_pinctrl_put(amlatvdemod_devp->pin); |
289 | amlatvdemod_devp->pin = NULL; |
290 | } |
291 | /* reset adc pll flag */ |
292 | /* printk("\n%s: init atvdemod flag...\n",__func__); */ |
293 | adc_set_pll_cntl(0, 0x1); |
294 | atvdemod_state = ATVDEMOD_STATE_IDEL; |
295 | return 0; |
296 | } |
297 | |
298 | static int aml_atvdemod_suspend(struct aml_fe_dev *dev) |
299 | { |
300 | pr_info("%s\n", __func__); |
301 | if (atvdemod_state != ATVDEMOD_STATE_IDEL) { |
302 | aml_atvdemod_leave_mode(NULL, 0); |
303 | atvdemod_state = ATVDEMOD_STATE_SLEEP; |
304 | } |
305 | return 0; |
306 | } |
307 | |
308 | static int aml_atvdemod_resume(struct aml_fe_dev *dev) |
309 | { |
310 | pr_info("%s\n", __func__); |
311 | if (atvdemod_state == ATVDEMOD_STATE_SLEEP) |
312 | aml_atvdemod_enter_mode(NULL, 0); |
313 | return 0; |
314 | } |
315 | |
316 | /* |
317 | *static int aml_atvdemod_get_afc(struct dvb_frontend *fe,int *afc) |
318 | *{ |
319 | * return 0; |
320 | *} |
321 | */ |
322 | |
323 | /*ret:5~100;the val is bigger,the signal is better*/ |
324 | int aml_atvdemod_get_snr(struct dvb_frontend *fe) |
325 | { |
326 | #if 1 |
327 | return get_atvdemod_snr_val(); |
328 | #else |
329 | unsigned int snr_val; |
330 | int ret; |
331 | |
332 | snr_val = atv_dmd_rd_long(APB_BLOCK_ADDR_VDAGC, 0x50) >> 8; |
333 | /* snr_val:900000~0xffffff,ret:5~15 */ |
334 | if (snr_val > 900000) |
335 | ret = 15 - (snr_val - 900000)*10/(0xffffff - 900000); |
336 | /* snr_val:158000~900000,ret:15~30 */ |
337 | else if (snr_val > 158000) |
338 | ret = 30 - (snr_val - 158000)*15/(900000 - 158000); |
339 | /* snr_val:31600~158000,ret:30~50 */ |
340 | else if (snr_val > 31600) |
341 | ret = 50 - (snr_val - 31600)*20/(158000 - 31600); |
342 | /* snr_val:316~31600,ret:50~80 */ |
343 | else if (snr_val > 316) |
344 | ret = 80 - (snr_val - 316)*30/(31600 - 316); |
345 | /* snr_val:0~316,ret:80~100 */ |
346 | else |
347 | ret = 100 - (316 - snr_val)*20/316; |
348 | return ret; |
349 | #endif |
350 | } |
351 | EXPORT_SYMBOL(aml_atvdemod_get_snr); |
352 | |
353 | int aml_atvdemod_get_snr_ex(void) |
354 | { |
355 | #if 1 |
356 | return get_atvdemod_snr_val(); |
357 | #else |
358 | unsigned int snr_val; |
359 | int ret; |
360 | |
361 | snr_val = atv_dmd_rd_long(APB_BLOCK_ADDR_VDAGC, 0x50) >> 8; |
362 | /* snr_val:900000~0xffffff,ret:5~15 */ |
363 | if (snr_val > 900000) |
364 | ret = 15 - (snr_val - 900000)*10/(0xffffff - 900000); |
365 | /* snr_val:158000~900000,ret:15~30 */ |
366 | else if (snr_val > 158000) |
367 | ret = 30 - (snr_val - 158000)*15/(900000 - 158000); |
368 | /* snr_val:31600~158000,ret:30~50 */ |
369 | else if (snr_val > 31600) |
370 | ret = 50 - (snr_val - 31600)*20/(158000 - 31600); |
371 | /* snr_val:316~31600,ret:50~80 */ |
372 | else if (snr_val > 316) |
373 | ret = 80 - (snr_val - 316)*30/(31600 - 316); |
374 | /* snr_val:0~316,ret:80~100 */ |
375 | else |
376 | ret = 100 - (316 - snr_val)*20/316; |
377 | return ret; |
378 | #endif |
379 | } |
380 | EXPORT_SYMBOL(aml_atvdemod_get_snr_ex); |
381 | |
382 | /*tuner lock status & demod lock status should be same in silicon tuner*/ |
383 | static int aml_atvdemod_get_status(struct dvb_frontend *fe, void *stat) |
384 | { |
385 | int video_lock; |
386 | fe_status_t *status = (fe_status_t *) stat; |
387 | |
388 | retrieve_video_lock(&video_lock); |
389 | if ((video_lock & 0x1) == 0) { |
390 | /* *status = FE_HAS_LOCK;*/ |
391 | *status = FE_TIMEDOUT; |
392 | pr_info("video lock:locked\n"); |
393 | } else { |
394 | pr_info("video lock:unlocked\n"); |
395 | *status = FE_TIMEDOUT; |
396 | /* *status = FE_HAS_LOCK;*/ |
397 | } |
398 | return 0; |
399 | } |
400 | |
401 | /*tuner lock status & demod lock status should be same in silicon tuner*/ |
402 | /* force return lock, for atvdemo status not sure */ |
403 | static void aml_atvdemod_get_pll_status(struct dvb_frontend *fe, void *stat) |
404 | { |
405 | int vpll_lock; |
406 | fe_status_t *status = (fe_status_t *) stat; |
407 | |
408 | retrieve_vpll_carrier_lock(&vpll_lock); |
409 | if ((vpll_lock&0x1) == 0) { |
410 | *status = FE_HAS_LOCK; |
411 | pr_info("visual carrier lock:locked\n"); |
412 | } else { |
413 | pr_info("visual carrier lock:unlocked\n"); |
414 | *status = FE_TIMEDOUT; |
415 | /* *status = FE_HAS_LOCK;*/ |
416 | } |
417 | } |
418 | |
419 | static int aml_atvdemod_get_atv_status(struct dvb_frontend *fe, |
420 | struct atv_status_s *atv_status) |
421 | { |
422 | int vpll_lock = 0, line_lock = 0; |
423 | int try_std = 1; |
424 | int loop_cnt = 5; |
425 | int cnt = 10; |
426 | int try_std_cnt = 0; |
427 | static int last_report_freq; |
428 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
429 | |
430 | while (fe && atv_status && loop_cnt--) { |
431 | atv_status->afc = retrieve_vpll_carrier_afc(); |
432 | retrieve_vpll_carrier_lock(&vpll_lock); |
433 | line_lock = atv_dmd_rd_byte(APB_BLOCK_ADDR_VDAGC, 0x4f)&0x10; |
434 | if ((vpll_lock&0x1) == 0 || line_lock == 0) { |
435 | atv_status->atv_lock = 1; |
436 | try_std_cnt = 2; |
437 | while (try_std_cnt--) { |
438 | atv_status->afc = retrieve_vpll_carrier_afc(); |
439 | if (atv_status->afc > 1500 |
440 | && atvdemod_scan_mode) { |
441 | if ((c->analog.std & 0xff000000) |
442 | != V4L2_COLOR_STD_PAL) { |
443 | c->analog.std = |
444 | V4L2_COLOR_STD_PAL |
445 | | V4L2_STD_PAL_BG; |
446 | c->frequency += 1; |
447 | fe->ops.set_frontend(fe); |
448 | msleep(20); |
449 | } else { |
450 | c->analog.std = |
451 | V4L2_COLOR_STD_NTSC |
452 | | V4L2_STD_NTSC_M; |
453 | c->frequency += 1; |
454 | fe->ops.set_frontend(fe); |
455 | usleep_range(20*1000, |
456 | 20*1000+100); |
457 | } |
458 | atv_status->afc = |
459 | retrieve_vpll_carrier_afc(); |
460 | |
461 | cnt = 4; |
462 | while (cnt--) { |
463 | if (atv_status->afc < 1500) |
464 | break; |
465 | atv_status->afc = |
466 | retrieve_vpll_carrier_afc(); |
467 | usleep_range(5*1000, 5*1000+100); |
468 | } |
469 | if (atv_status->afc < 1500) |
470 | break; |
471 | } |
472 | } |
473 | |
474 | if (atv_status->afc > 4000 && !atvdemod_scan_mode) |
475 | atv_status->atv_lock = 0; |
476 | |
477 | if (last_report_freq != c->frequency) |
478 | last_report_freq = c->frequency; |
479 | |
480 | if (atvdemod_scan_mode) |
481 | pr_err("%s,lock freq:%d, afc:%d\n", __func__, |
482 | c->frequency, atv_status->afc); |
483 | break; |
484 | |
485 | } else if (try_std%3 == 0 && atvdemod_scan_mode) { |
486 | if ((c->analog.std & 0xff000000) |
487 | != V4L2_COLOR_STD_PAL) { |
488 | c->analog.std = |
489 | V4L2_COLOR_STD_PAL | V4L2_STD_PAL_DK; |
490 | } |
491 | if (abs(c->frequency - last_report_freq) > 1000000) { |
492 | c->frequency -= 500000; |
493 | pr_err("@@@ %s freq:%d unlock,try back 0.5M\n", |
494 | __func__, c->frequency); |
495 | } else |
496 | c->frequency += 1; |
497 | fe->ops.set_frontend(fe); |
498 | usleep_range(10*1000, 10*1000+100); |
499 | } |
500 | if (atvdemod_scan_mode) |
501 | pr_err("@@@ %s freq:%d unlock, read lock again\n", |
502 | __func__, c->frequency); |
503 | if (atvdemod_scan_mode == 0) |
504 | usleep_range(10*1000, 10*1000+100); |
505 | else |
506 | usleep_range(1000, 1200); |
507 | |
508 | atv_status->atv_lock = 0; |
509 | try_std++; |
510 | } |
511 | if (atvdemod_scan_mode == 0) { |
512 | if (abs(atv_status->afc) < 20) |
513 | afc_wave_cnt = 0; |
514 | if (500*1000 > abs(last_frq - c->frequency) |
515 | && 20 < abs(atv_status->afc) |
516 | && 200 > abs(atv_status->afc)) { |
517 | afc_wave_cnt++; |
518 | pr_err("%s play mode,afc_wave_cnt:%d\n", |
519 | __func__, afc_wave_cnt); |
520 | if (afc_wave_cnt < 20) { |
521 | atv_status->afc = 0; |
522 | pr_err("%s, afc is wave,ignore\n", __func__); |
523 | } |
524 | } |
525 | } |
526 | return 0; |
527 | } |
528 | |
529 | void aml_atvdemod_set_params(struct dvb_frontend *fe, |
530 | struct analog_parameters *p) |
531 | { |
532 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; |
533 | |
534 | if (fe->ops.info.type == FE_ANALOG) { |
535 | if ((p->std != amlatvdemod_devp->parm.std) || |
536 | (p->tuner_id == AM_TUNER_R840) || |
537 | (p->tuner_id == AM_TUNER_SI2151) || |
538 | (p->tuner_id == AM_TUNER_MXL661)) { |
539 | amlatvdemod_devp->parm.std = p->std; |
540 | amlatvdemod_devp->parm.if_freq = p->if_freq; |
541 | amlatvdemod_devp->parm.if_inv = p->if_inv; |
542 | amlatvdemod_devp->parm.tuner_id = p->tuner_id; |
543 | /* open AGC if needed */ |
544 | if (amlatvdemod_devp->pin != NULL) |
545 | devm_pinctrl_put(amlatvdemod_devp->pin); |
546 | if (amlatvdemod_devp->pin_name) |
547 | amlatvdemod_devp->pin = |
548 | devm_pinctrl_get_select(amlatvdemod_devp->dev, |
549 | amlatvdemod_devp->pin_name); |
550 | atv_dmd_set_std(); |
551 | last_frq = c->frequency; |
552 | last_std = c->analog.std; |
553 | pr_info("[amlatvdemod..]%s set std color %s, audio type %s.\n", |
554 | __func__, |
555 | v4l2_std_to_str(0xff000000&amlatvdemod_devp->parm.std), |
556 | v4l2_std_to_str(0xffffff&amlatvdemod_devp->parm.std)); |
557 | pr_info("[amlatvdemod..]%s set if_freq 0x%x, if_inv 0x%x.\n", |
558 | __func__, amlatvdemod_devp->parm.if_freq, |
559 | amlatvdemod_devp->parm.if_inv); |
560 | } |
561 | } |
562 | } |
563 | static int aml_atvdemod_get_afc(struct dvb_frontend *fe, s32 *afc) |
564 | { |
565 | *afc = retrieve_vpll_carrier_afc(); |
566 | pr_info("[amlatvdemod..]%s afc %d.\n", __func__, *afc); |
567 | return 0; |
568 | } |
569 | |
570 | static int aml_atvdemod_get_ops(struct aml_fe_dev *dev, int mode, void *ops) |
571 | { |
572 | struct analog_demod_ops *aml_analog_ops = |
573 | (struct analog_demod_ops *)ops; |
574 | if (!ops) { |
575 | pr_dbg("[amlatvdemod..]%s null pointer error.\n", __func__); |
576 | return -1; |
577 | } |
578 | aml_analog_ops->get_afc = aml_atvdemod_get_afc; |
579 | aml_analog_ops->get_snr = aml_atvdemod_get_snr; |
580 | aml_analog_ops->get_status = aml_atvdemod_get_status; |
581 | aml_analog_ops->set_params = aml_atvdemod_set_params; |
582 | aml_analog_ops->get_pll_status = aml_atvdemod_get_pll_status; |
583 | aml_analog_ops->get_atv_status = aml_atvdemod_get_atv_status; |
584 | return 0; |
585 | } |
586 | |
587 | static struct aml_fe_drv aml_atvdemod_drv = { |
588 | .name = "aml_atv_demod", |
589 | .capability = AM_FE_ANALOG, |
590 | .id = AM_ATV_DEMOD_AML, |
591 | .get_ops = aml_atvdemod_get_ops, |
592 | .init = aml_atvdemod_fe_init, |
593 | .enter_mode = aml_atvdemod_enter_mode, |
594 | .leave_mode = aml_atvdemod_leave_mode, |
595 | .suspend = aml_atvdemod_suspend, |
596 | .resume = aml_atvdemod_resume, |
597 | }; |
598 | |
599 | struct class *aml_atvdemod_clsp; |
600 | |
601 | static void aml_atvdemod_dt_parse(struct platform_device *pdev) |
602 | { |
603 | struct device_node *node; |
604 | unsigned int val; |
605 | int ret; |
606 | |
607 | node = pdev->dev.of_node; |
608 | /* get integer value */ |
609 | if (node) { |
610 | ret = of_property_read_u32(node, "reg_23cf", &val); |
611 | if (ret) |
612 | pr_dbg("Can't find reg_23cf.\n"); |
613 | else |
614 | reg_23cf = val; |
615 | ret = of_property_read_u32(node, "audio_gain_val", &val); |
616 | if (ret) |
617 | pr_dbg("Can't find audio_gain_val.\n"); |
618 | else |
619 | set_audio_gain_val(val); |
620 | ret = of_property_read_u32(node, "video_gain_val", &val); |
621 | if (ret) |
622 | pr_dbg("Can't find video_gain_val.\n"); |
623 | else |
624 | set_video_gain_val(val); |
625 | /* agc pin mux */ |
626 | ret = of_property_read_string(node, "pinctrl-names", |
627 | &amlatvdemod_devp->pin_name); |
628 | if (!ret) { |
629 | /* amlatvdemod_devp->pin = */ |
630 | /* devm_pinctrl_get_select(&pdev->dev, */ |
631 | /* amlatvdemod_devp->pin_name); */ |
632 | pr_dbg("atvdemod agc pinmux name:%s\n", |
633 | amlatvdemod_devp->pin_name); |
634 | } |
635 | } |
636 | } |
637 | static struct resource amlatvdemod_memobj; |
638 | void __iomem *amlatvdemod_reg_base; |
639 | void __iomem *amlatvdemod_hiu_reg_base; |
640 | void __iomem *amlatvdemod_periphs_reg_base; |
641 | int amlatvdemod_reg_read(unsigned int reg, unsigned int *val) |
642 | { |
643 | *val = readl(amlatvdemod_reg_base + reg); |
644 | return 0; |
645 | } |
646 | |
647 | int amlatvdemod_reg_write(unsigned int reg, unsigned int val) |
648 | { |
649 | writel(val, (amlatvdemod_reg_base + reg)); |
650 | return 0; |
651 | } |
652 | |
653 | int amlatvdemod_hiu_reg_read(unsigned int reg, unsigned int *val) |
654 | { |
655 | *val = readl(amlatvdemod_hiu_reg_base + ((reg - 0x1000)<<2)); |
656 | return 0; |
657 | } |
658 | |
659 | int amlatvdemod_hiu_reg_write(unsigned int reg, unsigned int val) |
660 | { |
661 | writel(val, (amlatvdemod_hiu_reg_base + ((reg - 0x1000)<<2))); |
662 | return 0; |
663 | } |
664 | int amlatvdemod_periphs_reg_read(unsigned int reg, unsigned int *val) |
665 | { |
666 | *val = readl(amlatvdemod_periphs_reg_base + ((reg - 0x1000)<<2)); |
667 | return 0; |
668 | } |
669 | |
670 | int amlatvdemod_periphs_reg_write(unsigned int reg, unsigned int val) |
671 | { |
672 | writel(val, (amlatvdemod_periphs_reg_base + ((reg - 0x1000)<<2))); |
673 | return 0; |
674 | } |
675 | |
676 | static int aml_atvdemod_probe(struct platform_device *pdev) |
677 | { |
678 | int ret = 0; |
679 | struct resource *res; |
680 | int size_io_reg; |
681 | |
682 | res = &amlatvdemod_memobj; |
683 | amlatvdemod_devp = kmalloc(sizeof(struct amlatvdemod_device_s), |
684 | GFP_KERNEL); |
685 | if (!amlatvdemod_devp) |
686 | goto fail_alloc_region; |
687 | memset(amlatvdemod_devp, 0, sizeof(struct amlatvdemod_device_s)); |
688 | amlatvdemod_devp->clsp = class_create(THIS_MODULE, |
689 | ATVDEMOD_DEVICE_NAME); |
690 | if (!amlatvdemod_devp->clsp) |
691 | goto fail_create_class; |
692 | ret = class_create_file(amlatvdemod_devp->clsp, |
693 | &class_attr_atvdemod_debug); |
694 | if (ret) |
695 | goto fail_class_create_file; |
696 | amlatvdemod_devp->dev = &pdev->dev; |
697 | |
698 | /*reg mem*/ |
699 | pr_info("%s:amlatvdemod start get ioremap .\n", __func__); |
700 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
701 | if (!res) { |
702 | dev_err(&pdev->dev, "missing memory resource\n"); |
703 | return -ENODEV; |
704 | } |
705 | size_io_reg = resource_size(res); |
706 | pr_info("amlatvdemod_probe reg=%p,size=%x\n", |
707 | (void *)res->start, size_io_reg); |
708 | amlatvdemod_reg_base = |
709 | devm_ioremap_nocache(&pdev->dev, res->start, size_io_reg); |
710 | if (!amlatvdemod_reg_base) { |
711 | dev_err(&pdev->dev, "amlatvdemod ioremap failed\n"); |
712 | return -ENOMEM; |
713 | } |
714 | pr_info("%s: amlatvdemod maped reg_base =%p, size=%x\n", |
715 | __func__, amlatvdemod_reg_base, size_io_reg); |
716 | /*remap hiu mem*/ |
717 | amlatvdemod_hiu_reg_base = ioremap(0xc883c000, 0x2000); |
718 | /*remap periphs mem*/ |
719 | amlatvdemod_periphs_reg_base = ioremap(0xc8834000, 0x2000); |
720 | |
721 | /*initialize the tuner common struct and register*/ |
722 | aml_register_fe_drv(AM_DEV_ATV_DEMOD, &aml_atvdemod_drv); |
723 | |
724 | aml_atvdemod_dt_parse(pdev); |
725 | pr_dbg("[amlatvdemod.] : probe ok.\n"); |
726 | return 0; |
727 | |
728 | fail_class_create_file: |
729 | pr_dbg("[amlatvdemod.] : atvdemod class file create error.\n"); |
730 | class_destroy(amlatvdemod_devp->clsp); |
731 | fail_create_class: |
732 | pr_dbg("[amlatvdemod.] : atvdemod class create error.\n"); |
733 | kfree(amlatvdemod_devp); |
734 | fail_alloc_region: |
735 | pr_dbg("[amlatvdemod.] : atvdemod alloc error.\n"); |
736 | pr_dbg("[amlatvdemod.] : atvdemod_init fail.\n"); |
737 | return ret; |
738 | } |
739 | |
740 | static int __exit aml_atvdemod_remove(struct platform_device *pdev) |
741 | { |
742 | if (amlatvdemod_devp == NULL) |
743 | return -1; |
744 | class_destroy(amlatvdemod_devp->clsp); |
745 | aml_unregister_fe_drv(AM_DEV_ATV_DEMOD, &aml_atvdemod_drv); |
746 | kfree(amlatvdemod_devp); |
747 | pr_dbg("[amlatvdemod.] : amvecm_remove.\n"); |
748 | return 0; |
749 | } |
750 | |
751 | |
752 | static const struct of_device_id aml_atvdemod_dt_match[] = { |
753 | { |
754 | .compatible = "amlogic, aml_atv_demod", |
755 | }, |
756 | {}, |
757 | }; |
758 | |
759 | static struct platform_driver aml_atvdemod_driver = { |
760 | .driver = { |
761 | .name = "aml_atv_demod", |
762 | .owner = THIS_MODULE, |
763 | .of_match_table = aml_atvdemod_dt_match, |
764 | }, |
765 | .probe = aml_atvdemod_probe, |
766 | .remove = __exit_p(aml_atvdemod_remove), |
767 | }; |
768 | |
769 | |
770 | static int __init aml_atvdemod_init(void) |
771 | { |
772 | if (platform_driver_register(&aml_atvdemod_driver)) { |
773 | pr_err("failed to register amlatvdemod driver module\n"); |
774 | return -ENODEV; |
775 | } |
776 | pr_dbg("[amlatvdemod..]%s.\n", __func__); |
777 | return 0; |
778 | } |
779 | |
780 | static void __exit aml_atvdemod_exit(void) |
781 | { |
782 | platform_driver_unregister(&aml_atvdemod_driver); |
783 | pr_dbg("[amlatvdemod..]%s: driver removed ok.\n", __func__); |
784 | } |
785 | |
786 | MODULE_AUTHOR("dezhi.kong <dezhi.kong@amlogic.com>"); |
787 | MODULE_DESCRIPTION("aml atv demod device driver"); |
788 | MODULE_LICENSE("GPL"); |
789 | |
790 | fs_initcall(aml_atvdemod_init); |
791 | module_exit(aml_atvdemod_exit); |
792 |