summaryrefslogtreecommitdiff
path: root/drivers/stream_input/tv_frontend/atv_demod/atvdemod_frontend.c (plain)
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
40struct amlatvdemod_device_s *amlatvdemod_devp;
41#define AMLATVDEMOD_VER "Ref.2015/09/01a"
42
43static int afc_wave_cnt;
44static int last_frq, last_std;
45
46unsigned int reg_23cf = 0x88188832; /*IIR filter*/
47module_param(reg_23cf, uint, 0664);
48MODULE_PARM_DESC(reg_23cf, "\n reg_23cf\n");
49
50unsigned int atvdemod_scan_mode; /*IIR filter*/
51module_param(atvdemod_scan_mode, uint, 0664);
52MODULE_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
58static int atvdemod_state = ATVDEMOD_STATE_IDEL;
59
60int is_atvdemod_scan_mode(void)
61{
62 return atvdemod_scan_mode;
63}
64EXPORT_SYMBOL(is_atvdemod_scan_mode);
65
66static int aml_atvdemod_enter_mode(struct aml_fe *fe, int mode);
67/*static void sound_store(const char *buff, v4l2_std_id *std);*/
68static 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
217static 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}
230static CLASS_ATTR(atvdemod_debug, 0644, aml_atvdemod_show, aml_atvdemod_store);
231
232void 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
249static 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
261static 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
283static 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
298static 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
308static 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*/
324int 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}
351EXPORT_SYMBOL(aml_atvdemod_get_snr);
352
353int 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}
380EXPORT_SYMBOL(aml_atvdemod_get_snr_ex);
381
382/*tuner lock status & demod lock status should be same in silicon tuner*/
383static 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 */
403static 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
419static 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
529void 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}
563static 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
570static 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
587static 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
599struct class *aml_atvdemod_clsp;
600
601static 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}
637static struct resource amlatvdemod_memobj;
638void __iomem *amlatvdemod_reg_base;
639void __iomem *amlatvdemod_hiu_reg_base;
640void __iomem *amlatvdemod_periphs_reg_base;
641int amlatvdemod_reg_read(unsigned int reg, unsigned int *val)
642{
643 *val = readl(amlatvdemod_reg_base + reg);
644 return 0;
645}
646
647int amlatvdemod_reg_write(unsigned int reg, unsigned int val)
648{
649 writel(val, (amlatvdemod_reg_base + reg));
650 return 0;
651}
652
653int 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
659int 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}
664int 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
670int 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
676static 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
728fail_class_create_file:
729 pr_dbg("[amlatvdemod.] : atvdemod class file create error.\n");
730 class_destroy(amlatvdemod_devp->clsp);
731fail_create_class:
732 pr_dbg("[amlatvdemod.] : atvdemod class create error.\n");
733 kfree(amlatvdemod_devp);
734fail_alloc_region:
735 pr_dbg("[amlatvdemod.] : atvdemod alloc error.\n");
736 pr_dbg("[amlatvdemod.] : atvdemod_init fail.\n");
737 return ret;
738}
739
740static 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
752static const struct of_device_id aml_atvdemod_dt_match[] = {
753 {
754 .compatible = "amlogic, aml_atv_demod",
755 },
756 {},
757};
758
759static 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
770static 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
780static 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
786MODULE_AUTHOR("dezhi.kong <dezhi.kong@amlogic.com>");
787MODULE_DESCRIPTION("aml atv demod device driver");
788MODULE_LICENSE("GPL");
789
790fs_initcall(aml_atvdemod_init);
791module_exit(aml_atvdemod_exit);
792