blob: 2e40179b77bea1058cfd1f090f5c8b83820a1192
1 | /* |
2 | * Copyright (C) 2017 Amlogic, Inc. All rights reserved. |
3 | * |
4 | * This program is free software; you can redistribute it and/or modify |
5 | * it under the terms of the GNU General Public License as published by |
6 | * the Free Software Foundation; either version 2 of the License, or |
7 | * (at your option) any later version. |
8 | * |
9 | * This program is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
12 | * more details. |
13 | * |
14 | * You should have received a copy of the GNU General Public License along |
15 | * with this program; if not, write to the Free Software Foundation, Inc., |
16 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
17 | * |
18 | * Description: |
19 | */ |
20 | #include <linux/version.h> |
21 | #include <linux/kernel.h> |
22 | #include <linux/module.h> |
23 | #include <linux/mutex.h> |
24 | #include <linux/wait.h> |
25 | #include <linux/string.h> |
26 | #include <linux/interrupt.h> |
27 | #include <linux/fs.h> |
28 | #include <linux/cdev.h> |
29 | #include <linux/device.h> |
30 | #include <linux/spinlock.h> |
31 | #include <linux/fcntl.h> |
32 | //#include <asm/irq.h> |
33 | #include <linux/uaccess.h> |
34 | #include <linux/poll.h> |
35 | #include <linux/delay.h> |
36 | #include <linux/platform_device.h> |
37 | #include <linux/gpio.h> |
38 | #include <linux/string.h> |
39 | #include <linux/pinctrl/consumer.h> |
40 | #include <linux/reset.h> |
41 | #include <linux/amlogic/media/utils/amstream.h> |
42 | //#include <linux/clk.h> |
43 | #include "c_stb_define.h" |
44 | #include "c_stb_regs_define.h" |
45 | #include "../aml_dvb.h" |
46 | #include "dvb_reg.h" |
47 | |
48 | #include "../../../tv_frontend/aml_fe.h" |
49 | #include "demod_gt.h" |
50 | #include "../../../../common/media_clock/switch/amports_gate.h" |
51 | |
52 | #define pr_error(fmt, args...) printk("DVB: " fmt, ## args) |
53 | #define pr_inf(fmt, args...) printk("DVB: " fmt, ## args) |
54 | |
55 | typedef enum __demod_type |
56 | { |
57 | DEMOD_INVALID, |
58 | DEMOD_INTERNAL, |
59 | DEMOD_ATBM8881, |
60 | DEMOD_MAX_NUM |
61 | }demod_type; |
62 | |
63 | typedef enum __tuner_type |
64 | { |
65 | TUNER_INVALID, |
66 | TUNER_SI2151, |
67 | TUNER_MXL661, |
68 | TUNER_SI2159, |
69 | TUNER_R842, |
70 | TUNER_R840, |
71 | TUNER_MAX_NUM |
72 | }tuner_type; |
73 | |
74 | static struct dvb_frontend *frontend[FE_DEV_COUNT] = {NULL, NULL}; |
75 | static demod_type s_demod_type[FE_DEV_COUNT] = {DEMOD_INVALID, DEMOD_INVALID}; |
76 | static tuner_type s_tuner_type[FE_DEV_COUNT] = {TUNER_INVALID, TUNER_INVALID}; |
77 | |
78 | static int dvb_attach_tuner(struct dvb_frontend *fe, struct aml_tuner *tuner, tuner_type *type) |
79 | { |
80 | struct tuner_config *cfg = &tuner->cfg; |
81 | struct i2c_adapter *i2c_adap = tuner->i2c_adp; |
82 | |
83 | switch (cfg->id) { |
84 | case AM_TUNER_R840: |
85 | if (!dvb_attach(r840_attach, fe, i2c_adap, cfg)) { |
86 | pr_error("dvb attach r840_attach tuner error\n"); |
87 | return -1; |
88 | } else { |
89 | pr_inf("r840_attach attach sucess\n"); |
90 | *type = TUNER_R840; |
91 | } |
92 | break; |
93 | case AM_TUNER_R842: |
94 | if (!dvb_attach(r842_attach, fe, i2c_adap, cfg)) { |
95 | pr_error("dvb attach r842_attach tuner error\n"); |
96 | return -1; |
97 | } else { |
98 | pr_inf("r842_attach attach sucess\n"); |
99 | *type = TUNER_R842; |
100 | } |
101 | break; |
102 | case AM_TUNER_SI2151: |
103 | if (!dvb_attach(si2151_attach, fe, i2c_adap, cfg)) { |
104 | pr_error("dvb attach tuner error\n"); |
105 | return -1; |
106 | } else { |
107 | pr_inf("si2151 attach sucess\n"); |
108 | *type = TUNER_SI2151; |
109 | } |
110 | break; |
111 | case AM_TUNER_SI2159: |
112 | if (!dvb_attach(si2159_attach, fe, i2c_adap, cfg)) { |
113 | pr_error("dvb attach si2159_attach tuner error\n"); |
114 | return -1; |
115 | } else { |
116 | pr_inf("si2159_attach attach sucess\n"); |
117 | *type = TUNER_SI2159; |
118 | } |
119 | break; |
120 | case AM_TUNER_MXL661: |
121 | if (!dvb_attach(mxl661_attach, fe, i2c_adap, cfg)) { |
122 | pr_error("dvb attach mxl661_attach tuner error\n"); |
123 | return -1; |
124 | } else { |
125 | pr_inf("mxl661_attach attach sucess\n"); |
126 | *type = TUNER_MXL661; |
127 | } |
128 | break; |
129 | default: |
130 | pr_error("can't support tuner type: %d\n", cfg->id); |
131 | break; |
132 | } |
133 | |
134 | return 0; |
135 | } |
136 | |
137 | ssize_t stb_show_tuner_setting(struct class *class, |
138 | struct class_attribute *attr, char *buf) |
139 | { |
140 | struct aml_dvb *dvb = aml_get_dvb_device(); |
141 | |
142 | if (dvb->tuner_cur >= 0) |
143 | pr_inf("dvb current attatch tuner %d, id: %d\n", |
144 | dvb->tuner_cur, dvb->tuners[dvb->tuner_cur].cfg.id); |
145 | else |
146 | pr_inf("dvb has no attatch tuner.\n"); |
147 | |
148 | return 0; |
149 | } |
150 | |
151 | ssize_t stb_store_tuner_setting(struct class *class, |
152 | struct class_attribute *attr, |
153 | const char *buf, size_t count) |
154 | { |
155 | int n = 0, i = 0, val = 0; |
156 | unsigned long tmp = 0; |
157 | char *buf_orig = NULL, *ps = NULL, *token = NULL; |
158 | char *parm[4] = { NULL }; |
159 | struct aml_dvb *dvb = aml_get_dvb_device(); |
160 | int tuner_id = 0; |
161 | struct aml_tuner *tuner = NULL; |
162 | |
163 | buf_orig = kstrdup(buf, GFP_KERNEL); |
164 | ps = buf_orig; |
165 | |
166 | while (1) { |
167 | token = strsep(&ps, "\n "); |
168 | if (token == NULL) |
169 | break; |
170 | if (*token == '\0') |
171 | continue; |
172 | parm[n++] = token; |
173 | } |
174 | |
175 | if (parm[0] && kstrtoul(parm[0], 10, &tmp) == 0) { |
176 | val = tmp; |
177 | |
178 | for (i = 0; i < dvb->tuner_num; ++i) { |
179 | if (dvb->tuners[i].cfg.id == val) { |
180 | tuner_id = dvb->tuners[i].cfg.id; |
181 | break; |
182 | } |
183 | } |
184 | |
185 | if (tuner_id == 0 || dvb->tuner_cur == i) { |
186 | pr_error("%s: set nonsupport or the same tuner %d.\n", |
187 | __func__, val); |
188 | goto EXIT; |
189 | } |
190 | |
191 | dvb->tuner_cur = i; |
192 | |
193 | for (i = 0; i < FE_DEV_COUNT; i++) { |
194 | tuner = &dvb->tuners[dvb->tuner_cur]; |
195 | |
196 | if (frontend[i] == NULL) |
197 | continue; |
198 | |
199 | if (dvb_attach_tuner(frontend[i], tuner, &s_tuner_type[i]) < 0) { |
200 | pr_error("attach tuner %d failed\n", dvb->tuner_cur); |
201 | goto EXIT; |
202 | } |
203 | } |
204 | |
205 | pr_error("%s: attach tuner %d done.\n", __func__, dvb->tuners[dvb->tuner_cur].cfg.id); |
206 | } |
207 | |
208 | EXIT: |
209 | |
210 | return count; |
211 | } |
212 | |
213 | |
214 | int frontend_probe(struct platform_device *pdev) |
215 | { |
216 | struct amlfe_exp_config config; |
217 | char buf[32]; |
218 | const char *str = NULL; |
219 | struct device_node *node_tuner = NULL; |
220 | struct device_node *node_i2c = NULL; |
221 | u32 i2c_addr = 0xFFFFFFFF; |
222 | struct tuner_config *cfg = NULL; |
223 | u32 value = 0; |
224 | int i = 0; |
225 | int ret =0; |
226 | int j = 0; |
227 | struct aml_dvb *advb = aml_get_dvb_device(); |
228 | |
229 | for (i=0; i<FE_DEV_COUNT; i++) { |
230 | memset(buf, 0, 32); |
231 | snprintf(buf, sizeof(buf), "fe%d_mode", i); |
232 | ret = of_property_read_string(pdev->dev.of_node, buf, &str); |
233 | if (ret) { |
234 | continue; |
235 | } |
236 | if (!strcmp(str,"internal")) |
237 | { |
238 | config.set_mode = 0; |
239 | frontend[i] = dvb_attach(aml_dtvdm_attach,&config); |
240 | if (frontend[i] == NULL) { |
241 | pr_error("dvb attach demod error\n"); |
242 | goto error_fe; |
243 | } else { |
244 | pr_inf("dtvdemod attatch sucess\n"); |
245 | s_demod_type[i] = DEMOD_INTERNAL; |
246 | } |
247 | |
248 | memset(&cfg, 0, sizeof(struct tuner_config)); |
249 | memset(buf, 0, 32); |
250 | snprintf(buf, sizeof(buf), "fe%d_tuner",i); |
251 | node_tuner = of_parse_phandle(pdev->dev.of_node, buf, 0); |
252 | if (!node_tuner){ |
253 | pr_err("can't find tuner.\n"); |
254 | goto error_fe; |
255 | } |
256 | ret = of_property_read_u32(node_tuner, "tuner_num", &value); |
257 | if (ret) { |
258 | pr_err("can't find tuner_num.\n"); |
259 | goto error_fe; |
260 | } else |
261 | advb->tuner_num = value; |
262 | |
263 | advb->tuners = kzalloc(sizeof(struct aml_tuner) * advb->tuner_num, GFP_KERNEL); |
264 | if (!advb->tuners) { |
265 | pr_err("can't kzalloc for tuners.\n"); |
266 | goto error_fe; |
267 | } |
268 | |
269 | ret = of_property_read_u32(node_tuner, "tuner_cur", &value); |
270 | if (ret) { |
271 | pr_err("can't find tuner_cur, use default 0.\n"); |
272 | advb->tuner_cur = -1; |
273 | } else |
274 | advb->tuner_cur = value; |
275 | |
276 | for (j = 0; j < advb->tuner_num; ++j) { |
277 | snprintf(buf, sizeof(buf), "tuner_name_%d", j); |
278 | ret = of_property_read_string(node_tuner, buf, &str); |
279 | if (ret) { |
280 | //pr_error("tuner%d type error\n",i); |
281 | ret = 0; |
282 | continue; |
283 | } else { |
284 | if (!strncmp(str, "mxl661_tuner", 12)) |
285 | advb->tuners[j].cfg.id = AM_TUNER_MXL661; |
286 | else if (!strncmp(str, "si2151_tuner", 12)) |
287 | advb->tuners[j].cfg.id = AM_TUNER_SI2151; |
288 | else if (!strncmp(str, "si2159_tuner", 12)) |
289 | advb->tuners[j].cfg.id = AM_TUNER_SI2159; |
290 | else if (!strncmp(str, "r840_tuner", 10)) |
291 | advb->tuners[j].cfg.id = AM_TUNER_R840; |
292 | else if (!strncmp(str, "r842_tuner", 10)) |
293 | advb->tuners[j].cfg.id = AM_TUNER_R842; |
294 | else { |
295 | pr_err("nonsupport tuner: %s.\n", str); |
296 | advb->tuners[j].cfg.id = AM_TUNER_NONE; |
297 | } |
298 | } |
299 | |
300 | snprintf(buf, sizeof(buf), "tuner_i2c_adap_%d", j); |
301 | node_i2c = of_parse_phandle(node_tuner, buf, 0); |
302 | if (!node_i2c) { |
303 | pr_error("tuner_i2c_adap_id error\n"); |
304 | } else { |
305 | advb->tuners[j].i2c_adp = of_find_i2c_adapter_by_node(node_i2c); |
306 | of_node_put(node_i2c); |
307 | if (advb->tuners[j].i2c_adp == NULL) { |
308 | pr_error("i2c_get_adapter error\n"); |
309 | of_node_put(node_tuner); |
310 | goto error_fe; |
311 | } |
312 | } |
313 | |
314 | snprintf(buf, sizeof(buf), "tuner_i2c_addr_%d", j); |
315 | ret = of_property_read_u32(node_tuner, buf, &i2c_addr); |
316 | if (ret) { |
317 | pr_error("i2c_addr error\n"); |
318 | } |
319 | else |
320 | advb->tuners[j].cfg.i2c_addr = i2c_addr; |
321 | |
322 | snprintf(buf, sizeof(buf), "tuner_xtal_%d", j); |
323 | ret = of_property_read_u32(node_tuner, buf, &value); |
324 | if (ret) |
325 | pr_err("tuner_xtal error.\n"); |
326 | else |
327 | advb->tuners[j].cfg.xtal = value; |
328 | |
329 | snprintf(buf, sizeof(buf), "tuner_xtal_mode_%d", j); |
330 | ret = of_property_read_u32(node_tuner, buf, &value); |
331 | if (ret) |
332 | pr_err("tuner_xtal_mode error.\n"); |
333 | else |
334 | advb->tuners[j].cfg.xtal_mode = value; |
335 | |
336 | snprintf(buf, sizeof(buf), "tuner_xtal_cap_%d", j); |
337 | ret = of_property_read_u32(node_tuner, buf, &value); |
338 | if (ret) |
339 | pr_err("tuner_xtal_cap error.\n"); |
340 | else |
341 | advb->tuners[j].cfg.xtal_cap = value; |
342 | } |
343 | |
344 | of_node_put(node_tuner); |
345 | |
346 | /* define general-purpose callback pointer */ |
347 | frontend[i]->callback = NULL; |
348 | |
349 | if (advb->tuner_cur >= 0) { |
350 | if (dvb_attach_tuner(frontend[i], &advb->tuners[advb->tuner_cur], &s_tuner_type[i]) < 0) { |
351 | pr_error("attach tuner failed\n"); |
352 | goto error_fe; |
353 | } |
354 | } |
355 | |
356 | ret = dvb_register_frontend(&advb->dvb_adapter, frontend[i]); |
357 | if (ret) { |
358 | pr_error("register dvb frontend failed\n"); |
359 | goto error_fe; |
360 | } |
361 | } else if(!strcmp(str,"external")) { |
362 | const char *name = NULL; |
363 | struct amlfe_demod_config config; |
364 | |
365 | config.dev_id = i; |
366 | memset(buf, 0, 32); |
367 | snprintf(buf, sizeof(buf), "fe%d_demod",i); |
368 | ret = of_property_read_string(pdev->dev.of_node, buf, &name); |
369 | if (ret) { |
370 | ret = 0; |
371 | continue; |
372 | } |
373 | |
374 | memset(buf, 0, 32); |
375 | snprintf(buf, sizeof(buf), "fe%d_i2c_adap_id",i); |
376 | node_i2c = of_parse_phandle(pdev->dev.of_node,buf,0); |
377 | if (!node_i2c) { |
378 | pr_error("demod%d_i2c_adap_id error\n", i); |
379 | } else { |
380 | config.i2c_adap = of_find_i2c_adapter_by_node(node_i2c); |
381 | of_node_put(node_i2c); |
382 | if (config.i2c_adap == NULL) { |
383 | pr_error("i2c_get_adapter error\n"); |
384 | goto error_fe; |
385 | } |
386 | } |
387 | |
388 | memset(buf, 0, 32); |
389 | snprintf(buf, sizeof(buf), "fe%d_demod_i2c_addr",i); |
390 | ret = of_property_read_u32(pdev->dev.of_node, buf,&config.i2c_addr); |
391 | if (ret) { |
392 | pr_error("i2c_addr error\n"); |
393 | goto error_fe; |
394 | } |
395 | |
396 | memset(buf, 0, 32); |
397 | snprintf(buf, sizeof(buf), "fe%d_ts",i); |
398 | ret = of_property_read_u32(pdev->dev.of_node, buf,&config.ts); |
399 | if (ret) { |
400 | pr_error("ts error\n"); |
401 | goto error_fe; |
402 | } |
403 | |
404 | memset(buf, 0, 32); |
405 | snprintf(buf, sizeof(buf), "fe%d_reset_gpio",i); |
406 | ret = of_property_read_string(pdev->dev.of_node, buf, &str); |
407 | if (!ret) { |
408 | config.reset_gpio = |
409 | of_get_named_gpio_flags(pdev->dev.of_node, |
410 | buf, 0, NULL); |
411 | pr_inf("%s: %d\n", buf, config.reset_gpio); |
412 | } else { |
413 | config.reset_gpio = -1; |
414 | pr_error("cannot find resource \"%s\"\n", buf); |
415 | goto error_fe; |
416 | } |
417 | |
418 | memset(buf, 0, 32); |
419 | snprintf(buf, sizeof(buf), "fe%d_reset_value",i); |
420 | ret = of_property_read_u32(pdev->dev.of_node, buf,&config.reset_value); |
421 | if (ret) { |
422 | pr_error("reset_value error\n"); |
423 | goto error_fe; |
424 | } |
425 | |
426 | if (!strcmp(name,"Atbm8881")) { |
427 | frontend[i] = dvb_attach(atbm8881_attach,&config); |
428 | if (frontend[i] == NULL) { |
429 | pr_error("dvb attach demod error\n"); |
430 | goto error_fe; |
431 | } else { |
432 | pr_inf("dtvdemod attatch sucess\n"); |
433 | s_demod_type[i] = DEMOD_ATBM8881; |
434 | } |
435 | } |
436 | if (frontend[i]) { |
437 | ret = dvb_register_frontend(&advb->dvb_adapter, frontend[i]); |
438 | if (ret) { |
439 | pr_error("register dvb frontend failed\n"); |
440 | goto error_fe; |
441 | } |
442 | } |
443 | } |
444 | } |
445 | if (advb->tuners) |
446 | kfree(advb->tuners); |
447 | return 0; |
448 | error_fe: |
449 | for (i=0; i<FE_DEV_COUNT; i++) { |
450 | if (s_demod_type[i] == DEMOD_INTERNAL) { |
451 | dvb_detach(aml_dtvdm_attach); |
452 | frontend[i] = NULL; |
453 | s_demod_type[i] = DEMOD_INVALID; |
454 | }else if (s_demod_type[i] == DEMOD_ATBM8881) { |
455 | dvb_detach(atbm8881_attach); |
456 | frontend[i] = NULL; |
457 | s_demod_type[i] = DEMOD_INVALID; |
458 | } |
459 | if (s_tuner_type[i] == TUNER_SI2151) { |
460 | dvb_detach(si2151_attach); |
461 | s_tuner_type[i] = TUNER_INVALID; |
462 | }else if (s_tuner_type[i] == TUNER_MXL661) { |
463 | dvb_detach(mxl661_attach); |
464 | s_tuner_type[i] = TUNER_INVALID; |
465 | }else if (s_tuner_type[i] == TUNER_SI2159) { |
466 | dvb_detach(si2159_attach); |
467 | s_tuner_type[i] = TUNER_INVALID; |
468 | }else if (s_tuner_type[i] == TUNER_R842) { |
469 | dvb_detach(r842_attach); |
470 | s_tuner_type[i] = TUNER_INVALID; |
471 | }else if (s_tuner_type[i] == TUNER_R840) { |
472 | dvb_detach(r840_attach); |
473 | s_tuner_type[i] = TUNER_INVALID; |
474 | } |
475 | } |
476 | |
477 | if (advb->tuners) |
478 | kfree(advb->tuners); |
479 | |
480 | return 0; |
481 | } |
482 | |
483 | int frontend_remove(void) |
484 | { |
485 | int i; |
486 | |
487 | for (i=0; i<FE_DEV_COUNT; i++) { |
488 | if (s_demod_type[i] == DEMOD_INTERNAL) { |
489 | dvb_detach(aml_dtvdm_attach); |
490 | }else if (s_demod_type[i] == DEMOD_ATBM8881) { |
491 | dvb_detach(atbm8881_attach); |
492 | } |
493 | if (s_tuner_type[i] == TUNER_SI2151) { |
494 | dvb_detach(si2151_attach); |
495 | }else if (s_tuner_type[i] == TUNER_MXL661) { |
496 | dvb_detach(mxl661_attach); |
497 | }else if (s_tuner_type[i] == TUNER_SI2159) { |
498 | dvb_detach(si2159_attach); |
499 | }else if (s_tuner_type[i] == TUNER_R842) { |
500 | dvb_detach(r842_attach); |
501 | }else if (s_tuner_type[i] == TUNER_R840) { |
502 | dvb_detach(r840_attach); |
503 | } |
504 | |
505 | if (frontend[i] && \ |
506 | ( (s_tuner_type[i] == TUNER_SI2151) || (s_tuner_type[i] == TUNER_MXL661) || (s_tuner_type[i] == TUNER_SI2159) || (s_tuner_type[i] == TUNER_R842) || (s_tuner_type[i] == TUNER_R840)) \ |
507 | ) |
508 | { |
509 | dvb_unregister_frontend(frontend[i]); |
510 | dvb_frontend_detach(frontend[i]); |
511 | } |
512 | frontend[i] = NULL; |
513 | s_demod_type[i] = DEMOD_INVALID; |
514 | s_tuner_type[i] = TUNER_INVALID; |
515 | |
516 | } |
517 | return 0; |
518 | } |
519 | |
520 |