1 /*
2 * drivers/gpu/drm/sunxi/sunxi_device/sunxi_tv/sunxi_tv.c
3 *
4 * Copyright (c) 2007-2019 Allwinnertech Co., Ltd.
5 * Author: zhengxiaobin <zhengxiaobin@allwinnertech.com>
6 * Author: zhengwanyu <zhengwanyu@allwinnertech.com>
7 *
8 * sunxi tvout driver include cvbs out, YPbPr and VGA out
9 *
10 * This software is licensed under the terms of the GNU General Public
11 * License version 2, as published by the Free Software Foundation, and
12 * may be copied, distributed, and modified under those terms.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 */
20
21 #include <linux/dma-mapping.h>
22 #include <drm/drmP.h>
23 #include <linux/clk.h>
24 #include "sunxi_common.h"
25 #include "sunxi_tcon.h"
26 #include "sunxi_tv.h"
27
28 static struct drv_model_info *p_tv_drv;
29 static struct sunxi_tv *hwtv[MAX_TV_COUNT];
30 static unsigned int tv_count;
31
32 /*video timing definition start*/
33 static struct disp_video_timings cvbs_timing[] = {
34 {
35 .vic = 0,
36 .tv_mode = DISP_TV_MOD_NTSC,
37 .pixel_clk = 216000000,
38 .pixel_repeat = 0,
39 .x_res = 720,
40 .y_res = 480,
41 .hor_total_time = 858,
42 .hor_back_porch = 60,
43 .hor_front_porch = 16,
44 .hor_sync_time = 62,
45 .ver_total_time = 525,
46 .ver_back_porch = 30,
47 .ver_front_porch = 9,
48 .ver_sync_time = 6,
49 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
50 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
51 .b_interlace = 0,
52 .vactive_space = 0,
53 .trd_mode = 0,
54
55 },
56 {
57 .vic = 0,
58 .tv_mode = DISP_TV_MOD_PAL,
59 .pixel_clk = 216000000,
60 .pixel_repeat = 0,
61 .x_res = 720,
62 .y_res = 576,
63 .hor_total_time = 864,
64 .hor_back_porch = 68,
65 .hor_front_porch = 12,
66 .hor_sync_time = 64,
67 .ver_total_time = 625,
68 .ver_back_porch = 39,
69 .ver_front_porch = 5,
70 .ver_sync_time = 5,
71 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
72 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
73 .b_interlace = 0,
74 .vactive_space = 0,
75 .trd_mode = 0,
76 },
77 };
78
79 static struct disp_video_timings vga_timing[] = {
80 {
81 .vic = 0,
82 .tv_mode = DISP_VGA_MOD_1600_900P_60,
83 .pixel_clk = 108000000,
84 .pixel_repeat = 0,
85 .x_res = 1600,
86 .y_res = 900,
87 .hor_total_time = 1800,
88 .hor_back_porch = 96,
89 .hor_front_porch = 24,
90 .hor_sync_time = 80,
91 .ver_total_time = 1000,
92 .ver_back_porch = 96,
93 .ver_front_porch = 1,
94 .ver_sync_time = 3,
95 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
96 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
97 .b_interlace = 0,
98 .vactive_space = 0,
99 .trd_mode = 0,
100 },
101 {
102 .vic = 0,
103 .tv_mode = DISP_VGA_MOD_1440_900P_60,
104 .pixel_clk = 89000000,
105 .pixel_repeat = 0,
106 .x_res = 1440,
107 .y_res = 900,
108 .hor_total_time = 1600,
109 .hor_back_porch = 80,
110 .hor_front_porch = 48,
111 .hor_sync_time = 32,
112 .ver_total_time = 926,
113 .ver_back_porch = 17,
114 .ver_front_porch = 3,
115 .ver_sync_time = 6,
116 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
117 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
118 .b_interlace = 0,
119 .vactive_space = 0,
120 .trd_mode = 0,
121 },
122 {
123 .vic = 0,
124 .tv_mode = DISP_VGA_MOD_1366_768P_60,
125 .pixel_clk = 85800000,
126 .pixel_repeat = 0,
127 .x_res = 1366,
128 .y_res = 768,
129 .hor_total_time = 1792,
130 .hor_back_porch = 213,
131 .hor_front_porch = 70,
132 .hor_sync_time = 143,
133 .ver_total_time = 798,
134 .ver_back_porch = 24,
135 .ver_front_porch = 3,
136 .ver_sync_time = 3,
137 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
138 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
139 .b_interlace = 0,
140 .vactive_space = 0,
141 .trd_mode = 0,
142 },
143 {
144 .vic = 0,
145 .tv_mode = DISP_VGA_MOD_1280_800P_60,
146 .pixel_clk = 83500000,
147 .pixel_repeat = 0,
148 .x_res = 1280,
149 .y_res = 800,
150 .hor_total_time = 1680,
151 .hor_back_porch = 200,
152 .hor_front_porch = 72,
153 .hor_sync_time = 128,
154 .ver_total_time = 831,
155 .ver_back_porch = 22,
156 .ver_front_porch = 3,
157 .ver_sync_time = 6,
158 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
159 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
160 .b_interlace = 0,
161 .vactive_space = 0,
162 .trd_mode = 0,
163 },
164 {
165 .vic = 0,
166 .tv_mode = DISP_VGA_MOD_1024_768P_60,
167 .pixel_clk = 65000000,
168 .pixel_repeat = 0,
169 .x_res = 1024,
170 .y_res = 768,
171 .hor_total_time = 1344,
172 .hor_back_porch = 160,
173 .hor_front_porch = 24,
174 .hor_sync_time = 136,
175 .ver_total_time = 806,
176 .ver_back_porch = 29,
177 .ver_front_porch = 3,
178 .ver_sync_time = 6,
179 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
180 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
181 .b_interlace = 0,
182 .vactive_space = 0,
183 .trd_mode = 0,
184 },
185 {
186 .vic = 0,
187 .tv_mode = DISP_VGA_MOD_800_600P_60,
188 .pixel_clk = 40000000,
189 .pixel_repeat = 0,
190 .x_res = 800,
191 .y_res = 600,
192 .hor_total_time = 1056,
193 .hor_back_porch = 88,
194 .hor_front_porch = 40,
195 .hor_sync_time = 128,
196 .ver_total_time = 628,
197 .ver_back_porch = 23,
198 .ver_front_porch = 1,
199 .ver_sync_time = 4,
200 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
201 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
202 .b_interlace = 0,
203 .vactive_space = 0,
204 .trd_mode = 0,
205 },
206 {
207 .vic = 0,
208 .tv_mode = DISP_VGA_MOD_1280_720P_60,
209 .pixel_clk = 74250000,
210 .pixel_repeat = 0,
211 .x_res = 1280,
212 .y_res = 720,
213 .hor_total_time = 1650,
214 .hor_back_porch = 220,
215 .hor_front_porch = 110,
216 .hor_sync_time = 40,
217 .ver_total_time = 750,
218 .ver_back_porch = 20,
219 .ver_front_porch = 5,
220 .ver_sync_time = 5,
221 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
222 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
223 .b_interlace = 0,
224 .vactive_space = 0,
225 .trd_mode = 0,
226 },
227 {
228 .vic = 0,
229 .tv_mode = DISP_VGA_MOD_1920_1080P_60,
230 .pixel_clk = 148500000,
231 .pixel_repeat = 0,
232 .x_res = 1920,
233 .y_res = 1080,
234 .hor_total_time = 2200,
235 .hor_back_porch = 148,
236 .hor_front_porch = 88,
237 .hor_sync_time = 44,
238 .ver_total_time = 1125,
239 .ver_back_porch = 36,
240 .ver_front_porch = 4,
241 .ver_sync_time = 5,
242 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
243 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
244 .b_interlace = 0,
245 .vactive_space = 0,
246 .trd_mode = 0,
247 },
248 };
249
250 static struct disp_video_timings ypbpr_timing[] = {
251 {
252 .vic = 0,
253 .tv_mode = DISP_TV_MOD_NTSC,
254 .pixel_clk = 216000000,
255 .pixel_repeat = 0,
256 .x_res = 720,
257 .y_res = 480,
258 .hor_total_time = 858,
259 .hor_back_porch = 60,
260 .hor_front_porch = 16,
261 .hor_sync_time = 62,
262 .ver_total_time = 525,
263 .ver_back_porch = 30,
264 .ver_front_porch = 9,
265 .ver_sync_time = 6,
266 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
267 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
268 .b_interlace = 0,
269 .vactive_space = 0,
270 .trd_mode = 0,
271
272 },
273 {
274 .vic = 0,
275 .tv_mode = DISP_TV_MOD_PAL,
276 .pixel_clk = 216000000,
277 .pixel_repeat = 0,
278 .x_res = 720,
279 .y_res = 576,
280 .hor_total_time = 864,
281 .hor_back_porch = 68,
282 .hor_front_porch = 12,
283 .hor_sync_time = 64,
284 .ver_total_time = 625,
285 .ver_back_porch = 39,
286 .ver_front_porch = 5,
287 .ver_sync_time = 5,
288 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
289 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
290 .b_interlace = 0,
291 .vactive_space = 0,
292 .trd_mode = 0,
293 },
294 {
295 .vic = 0,
296 .tv_mode = DISP_TV_MOD_480I,
297 .pixel_clk = 216000000,
298 .pixel_repeat = 0,
299 .x_res = 720,
300 .y_res = 480,
301 .hor_total_time = 858,
302 .hor_back_porch = 57,
303 .hor_front_porch = 62,
304 .hor_sync_time = 19,
305 .ver_total_time = 525,
306 .ver_back_porch = 4,
307 .ver_front_porch = 1,
308 .ver_sync_time = 3,
309 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
310 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
311 .b_interlace = 1,
312 .vactive_space = 0,
313 .trd_mode = 0,
314 },
315 {
316 .vic = 0,
317 .tv_mode = DISP_TV_MOD_576I,
318 .pixel_clk = 216000000,
319 .pixel_repeat = 0,
320 .x_res = 720,
321 .y_res = 576,
322 .hor_total_time = 864,
323 .hor_back_porch = 69,
324 .hor_front_porch = 63,
325 .hor_sync_time = 12,
326 .ver_total_time = 625,
327 .ver_back_porch = 2,
328 .ver_front_porch = 44,
329 .ver_sync_time = 3,
330 .hor_sync_polarity = 0,/* 0: negative, 1: positive */
331 .ver_sync_polarity = 0,/* 0: negative, 1: positive */
332 .b_interlace = 1,
333 .vactive_space = 0,
334 .trd_mode = 0,
335 },
336 {
337 .vic = 0,
338 .tv_mode = DISP_TV_MOD_480P,
339 .pixel_clk = 54000000,
340 .pixel_repeat = 0,
341 .x_res = 720,
342 .y_res = 480,
343 .hor_total_time = 858,
344 .hor_back_porch = 60,
345 .hor_front_porch = 62,
346 .hor_sync_time = 16,
347 .ver_total_time = 525,
348 .ver_back_porch = 9,
349 .ver_front_porch = 30,
350 .ver_sync_time = 6,
351 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
352 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
353 .b_interlace = 0,
354 .vactive_space = 0,
355 .trd_mode = 0,
356 },
357 {
358 .vic = 0,
359 .tv_mode = DISP_TV_MOD_576P,
360 .pixel_clk = 54000000,
361 .pixel_repeat = 0,
362 .x_res = 720,
363 .y_res = 576,
364 .hor_total_time = 864,
365 .hor_back_porch = 68,
366 .hor_front_porch = 64,
367 .hor_sync_time = 12,
368 .ver_total_time = 625,
369 .ver_back_porch = 5,
370 .ver_front_porch = 39,
371 .ver_sync_time = 5,
372 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
373 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
374 .b_interlace = 0,
375 .vactive_space = 0,
376 .trd_mode = 0,
377 },
378 {
379 .vic = 0,
380 .tv_mode = DISP_TV_MOD_720P_60HZ,
381 .pixel_clk = 74250000,
382 .pixel_repeat = 0,
383 .x_res = 1280,
384 .y_res = 720,
385 .hor_total_time = 1650,
386 .hor_back_porch = 220,
387 .hor_front_porch = 40,
388 .hor_sync_time = 110,
389 .ver_total_time = 750,
390 .ver_back_porch = 5,
391 .ver_front_porch = 20,
392 .ver_sync_time = 5,
393 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
394 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
395 .b_interlace = 0,
396 .vactive_space = 0,
397 .trd_mode = 0,
398 },
399 {
400 .vic = 0,
401 .tv_mode = DISP_TV_MOD_720P_50HZ,
402 .pixel_clk = 74250000,
403 .pixel_repeat = 0,
404 .x_res = 1280,
405 .y_res = 720,
406 .hor_total_time = 1980,
407 .hor_back_porch = 220,
408 .hor_front_porch = 40,
409 .hor_sync_time = 440,
410 .ver_total_time = 750,
411 .ver_back_porch = 5,
412 .ver_front_porch = 20,
413 .ver_sync_time = 5,
414 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
415 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
416 .b_interlace = 0,
417 .vactive_space = 0,
418 .trd_mode = 0,
419 },
420 {
421 .vic = 0,
422 .tv_mode = DISP_TV_MOD_1080I_60HZ,
423 .pixel_clk = 74250000,
424 .pixel_repeat = 0,
425 .x_res = 1920,
426 .y_res = 1080,
427 .hor_total_time = 2200,
428 .hor_back_porch = 148,
429 .hor_front_porch = 44,
430 .hor_sync_time = 88,
431 .ver_total_time = 1125,
432 .ver_back_porch = 2,
433 .ver_front_porch = 38,
434 .ver_sync_time = 5,
435 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
436 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
437 .b_interlace = 1,
438 .vactive_space = 0,
439 .trd_mode = 0,
440 },
441 {
442 .vic = 0,
443 .tv_mode = DISP_TV_MOD_1080I_50HZ,
444 .pixel_clk = 74250000,
445 .pixel_repeat = 0,
446 .x_res = 1920,
447 .y_res = 1080,
448 .hor_total_time = 2640,
449 .hor_back_porch = 148,
450 .hor_front_porch = 44,
451 .hor_sync_time = 528,
452 .ver_total_time = 1125,
453 .ver_back_porch = 2,
454 .ver_front_porch = 38,
455 .ver_sync_time = 5,
456 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
457 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
458 .b_interlace = 1,
459 .vactive_space = 0,
460 .trd_mode = 0,
461 },
462 {
463 .vic = 0,
464 .tv_mode = DISP_TV_MOD_1080P_60HZ,
465 .pixel_clk = 148500000,
466 .pixel_repeat = 0,
467 .x_res = 1920,
468 .y_res = 1080,
469 .hor_total_time = 2200,
470 .hor_back_porch = 148,
471 .hor_front_porch = 44,
472 .hor_sync_time = 88,
473 .ver_total_time = 1125,
474 .ver_back_porch = 4,
475 .ver_front_porch = 36,
476 .ver_sync_time = 5,
477 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
478 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
479 .b_interlace = 0,
480 .vactive_space = 0,
481 .trd_mode = 0,
482 },
483 {
484 .vic = 0,
485 .tv_mode = DISP_TV_MOD_1080P_50HZ,
486 .pixel_clk = 148500000,
487 .pixel_repeat = 0,
488 .x_res = 1920,
489 .y_res = 1080,
490 .hor_total_time = 2640,
491 .hor_back_porch = 148,
492 .hor_front_porch = 44,
493 .hor_sync_time = 528,
494 .ver_total_time = 1125,
495 .ver_back_porch = 4,
496 .ver_front_porch = 36,
497 .ver_sync_time = 5,
498 .hor_sync_polarity = 1,/* 0: negative, 1: positive */
499 .ver_sync_polarity = 1,/* 0: negative, 1: positive */
500 .b_interlace = 0,
501 .vactive_space = 0,
502 .trd_mode = 0,
503 },
504 };
505 /*video timing definition end*/
506
sunxi_tv_get_tv(int tv_id)507 static struct sunxi_tv *sunxi_tv_get_tv(int tv_id)
508 {
509 if (tv_id > MAX_TV_COUNT) {
510 TV_ERR("tv_id:%d is too big!\n", tv_id);
511 return NULL;
512 }
513
514 return hwtv[tv_id];
515 }
516
517 /**
518 * @name :sunxi_tv_get_tv_count
519 * @brief :get the number of sunxi
520 * @return :the number of sunxi tv
521 */
sunxi_tv_get_tv_count(void)522 int sunxi_tv_get_tv_count(void)
523 {
524 return tv_count;
525 }
526
__pin_config(int sel,char * name)527 static int __pin_config(int sel, char *name)
528 {
529 int ret = 0;
530 char type_name[10] = {0};
531 struct device_node *node;
532 struct platform_device *pdev;
533 struct pinctrl *pctl;
534 struct pinctrl_state *state;
535
536 snprintf(type_name, sizeof(type_name), "tv%d", sel);
537
538 node = of_find_compatible_node(NULL, type_name, "allwinner,sunxi-tv");
539 if (!node) {
540 TV_ERR("of_find_tv_node %s fail\n", type_name);
541 ret = -EINVAL;
542 goto exit;
543 }
544
545 pdev = of_find_device_by_node(node);
546 if (!node) {
547 TV_ERR("of_find_device_by_node for %s fail\n", type_name);
548 ret = -EINVAL;
549 goto exit;
550 }
551
552 pctl = pinctrl_get(&pdev->dev);
553 if (IS_ERR(pctl)) {
554 TV_ERR("pinctrl_get for %s fail\n", type_name);
555 ret = PTR_ERR(pctl);
556 goto exit;
557 }
558
559 state = pinctrl_lookup_state(pctl, name);
560 if (IS_ERR(state)) {
561 TV_ERR("pinctrl_lookup_state for %s fail\n", type_name);
562 ret = PTR_ERR(state);
563 goto exit;
564 }
565
566 ret = pinctrl_select_state(pctl, state);
567 if (ret < 0) {
568 TV_ERR("pinctrl_select_state(%s)fail\n", type_name);
569 goto exit;
570 }
571
572 exit:
573 return ret;
574 }
575
tv_get_timing_list_num(struct sunxi_tv * p_tv)576 s32 tv_get_timing_list_num(struct sunxi_tv *p_tv)
577 {
578 if (!p_tv) {
579 TV_ERR("Null pointer!\n");
580 return 0;
581 }
582 if (p_tv->tv_type == DISP_TV_CVBS) {
583 return sizeof(cvbs_timing) / sizeof(struct disp_video_timings);
584 } else if (p_tv->tv_type == DISP_VGA) {
585 return sizeof(vga_timing) / sizeof(struct disp_video_timings);
586 } else {
587 return sizeof(ypbpr_timing) / sizeof(struct disp_video_timings);
588 }
589 }
590
tve_clk_enable(struct sunxi_tv * p_tv)591 static int tve_clk_enable(struct sunxi_tv *p_tv)
592 {
593 int ret = -1;
594
595 if (!p_tv) {
596 TV_ERR("Null pointer!\n");
597 goto OUT;
598 }
599
600 ret = clk_prepare_enable(p_tv->mclk);
601 if (ret != 0) {
602 TV_ERR("fail to enable tve%d's clk!\n", p_tv->id);
603 return ret;
604 }
605
606 OUT:
607 return ret;
608 }
609
610 /*static int tve_clk_disable(struct sunxi_tv *p_tv)
611 {
612 if (!p_tv) {
613 TV_ERR("Null pointer!\n");
614 return -1;
615 }
616 clk_disable(p_tv->mclk);
617 return 0;
618 }*/
619
tve_get_pixclk(struct sunxi_tv * p_tv,unsigned long * p_rate)620 static s32 tve_get_pixclk(struct sunxi_tv *p_tv, unsigned long *p_rate)
621 {
622 int i = 0, list_num = 0, ret = -1;
623 bool find = false;
624 struct disp_video_timings *info = NULL;
625
626 if (!p_rate || !p_tv)
627 goto OUT;
628
629 list_num = tv_get_timing_list_num(p_tv);
630 info = p_tv->video_info;
631 if (!info) {
632 TV_ERR("Null pointer!\n");
633 goto OUT;
634 }
635
636 for (i = 0; i < list_num; i++) {
637 if (info->tv_mode == p_tv->tv_mode) {
638 find = true;
639 break;
640 }
641 info++;
642 }
643 if (!find) {
644 TV_ERR("tv have no mode(%d)!\n", p_tv->tv_mode);
645 goto OUT;
646 } else {
647 *p_rate = info->pixel_clk;
648 ret = 0;
649 }
650 OUT:
651 return ret;
652 }
653
tve_clk_config(struct sunxi_tv * p_tv)654 static void tve_clk_config(struct sunxi_tv *p_tv)
655 {
656 int ret = 0;
657 unsigned long rate = 0, prate = 0;
658 unsigned long round = 0, parent_round_rate = 0;
659 signed long rate_diff = 0, prate_diff = 0, accuracy = 1000000;
660 unsigned int div = 1;
661
662 if (!p_tv) {
663 TV_ERR("Null pointer!\n");
664 return;
665 }
666
667 ret = tve_get_pixclk(p_tv, &rate);
668 if (ret)
669 TV_ERR("%s:tve_get_pixclk fail!\n", __func__);
670
671 round = clk_round_rate(p_tv->mclk, rate);
672 rate_diff = (long)(round - rate);
673 if ((rate_diff > accuracy) || (rate_diff < -accuracy)) {
674 for (accuracy = 1000000; accuracy <= 5000000;
675 accuracy += 1000000) {
676 for (div = 1; (rate * div) <= 984000000; div++) {
677 prate = rate * div;
678 parent_round_rate =
679 clk_round_rate(p_tv->mclk_parent, prate);
680 prate_diff = (long)(parent_round_rate - prate);
681 if ((prate_diff < accuracy) &&
682 (prate_diff > -accuracy)) {
683 ret = clk_set_rate(p_tv->mclk_parent,
684 prate);
685 ret += clk_set_rate(
686 p_tv->mclk, rate);
687 if (ret)
688 TV_ERR("fail to set rate(%ld) "
689 "fo tve%d's clock!\n",
690 rate, p_tv->id);
691 else
692 break;
693 }
694 }
695 if (rate * div > 984000000) {
696 TV_ERR("fail to set tve clk at %ld accuracy\n",
697 accuracy);
698 continue;
699 }
700 break;
701 }
702 } else {
703 prate = clk_get_rate(p_tv->mclk_parent);
704 ret = clk_set_rate(p_tv->mclk, rate);
705 if (ret)
706 TV_ERR("fail to set rate(%ld) fo tve%d's clock!\n",
707 rate, p_tv->id);
708 }
709
710 TV_DBG("parent prate=%lu(%lu), rate=%lu(%lu), tv_mode=%d\n",
711 clk_get_rate(p_tv->mclk_parent), prate,
712 clk_get_rate(p_tv->mclk), rate, p_tv->tv_mode);
713 }
714
715 /*static enum disp_tv_mode sunxi_tv_get_mode(int tv_id)
716 {
717 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
718
719 if (!p_tv) {
720 TV_ERR("Null pointer!\n");
721 return DISP_TV_MODE_NUM;
722 }
723
724 return p_tv->tv_mode;
725 }*/
726
sunxi_tv_get_video_timing(int tv_id,unsigned int tv_mode)727 struct disp_video_timings *sunxi_tv_get_video_timing(
728 int tv_id, unsigned int tv_mode)
729 {
730 int i, num;
731 struct disp_video_timings *timing;
732 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
733
734 if (!p_tv) {
735 TV_ERR("Null pointer!\n");
736 return NULL;
737 }
738
739 num = tv_get_timing_list_num(p_tv);
740 timing = p_tv->video_info;
741
742 for (i = 0; i < num; i++)
743 if (timing[i].tv_mode == tv_mode)
744 break;
745
746 if (i >= num) {
747 TV_ERR("cat NOT get timing from tv_mode:%u\n", tv_mode);
748 return NULL;
749 }
750
751 return &timing[i];
752
753 }
754
755
sunxi_tv_set_mode(int tv_id,enum disp_tv_mode tv_mode)756 int sunxi_tv_set_mode(int tv_id, enum disp_tv_mode tv_mode)
757 {
758 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
759
760 if (!p_tv) {
761 TV_ERR("Null pointer!\n");
762 return -1;
763 }
764
765 mutex_lock(&p_tv->mlock);
766 p_tv->tv_mode = tv_mode;
767 mutex_unlock(&p_tv->mlock);
768 return 0;
769 }
770
sunxi_tv_enable(int tv_id)771 int sunxi_tv_enable(int tv_id)
772 {
773 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
774
775 if (!p_tv) {
776 TV_ERR("Null pointer!\n");
777 return -1;
778 }
779
780 if (!p_tv->enable) {
781 if (p_tv->tv_type == DISP_VGA)
782 __pin_config(p_tv->id, "active");
783
784 tve_clk_config(p_tv);
785 tve_low_set_tv_mode(p_tv->id, p_tv->tv_mode, p_tv->cali);
786 tve_low_dac_enable(p_tv->id);
787 tve_low_open(p_tv->id);
788 mutex_lock(&p_tv->mlock);
789 p_tv->enable = 1;
790 mutex_unlock(&p_tv->mlock);
791 }
792 return 0;
793 }
794
sunxi_tv_disable(int tv_id)795 int sunxi_tv_disable(int tv_id)
796 {
797 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
798
799 if (!p_tv) {
800 TV_ERR("Null pointer!\n");
801 return -1;
802 }
803
804 TV_DBG("tv %d\n", p_tv->id);
805
806 mutex_lock(&p_tv->mlock);
807 if (p_tv->enable) {
808 tve_low_close(p_tv->id);
809 tve_low_dac_autocheck_enable(p_tv->id);
810 p_tv->enable = 0;
811 }
812 mutex_unlock(&p_tv->mlock);
813 if (p_tv->tv_type == DISP_VGA)
814 __pin_config(p_tv->id, "sleep");
815
816 return 0;
817 }
818
sunxi_tv_get_working_mode(int tv_id,struct sunxi_tv_work_mode * work_mode)819 int sunxi_tv_get_working_mode(int tv_id,
820 struct sunxi_tv_work_mode *work_mode)
821 {
822 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
823
824 if (!p_tv) {
825 TV_ERR("Null pointer!\n");
826 return 1;
827 }
828
829 /* vga interface is rgb mode. */
830 if (p_tv->tv_type == DISP_VGA)
831 work_mode->color_fmt = COLOR_FMT_RGB444;
832 else
833 work_mode->color_fmt = COLOR_FMT_YUV444;
834
835 return 0;
836 }
837
sunxi_tv_get_interface_type(int tv_id)838 enum disp_tv_output sunxi_tv_get_interface_type(int tv_id)
839 {
840 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
841
842 if (!p_tv) {
843 TV_ERR("Null pointer!\n");
844 return DISP_TV_NONE;
845 }
846
847 return p_tv->tv_type;
848 }
849
sunxi_tv_get_connect_status(int tv_id)850 int sunxi_tv_get_connect_status(int tv_id)
851 {
852 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
853
854 if (!p_tv) {
855 TV_ERR("Null pointer!\n");
856 return DISP_TV_NONE;
857 }
858
859 if (p_tv->tv_type == DISP_VGA ||
860 p_tv->tv_type == DISP_TV_YPBPR)
861 return 1;
862
863 return tve_low_get_dac_status(p_tv->id);
864 }
865
sunxi_tv_mode_support(int tv_id,enum disp_tv_mode tv_mode)866 int sunxi_tv_mode_support(int tv_id, enum disp_tv_mode tv_mode)
867 {
868 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
869 unsigned int i, list_num;
870 struct disp_video_timings *info;
871
872 if (!p_tv) {
873 TV_ERR("Null pointer!\n");
874 return 0;
875 }
876
877 list_num = tv_get_timing_list_num(p_tv);
878 if (!list_num) {
879 TV_ERR("list number is zero!\n");
880 return 0;
881 }
882
883 if (p_tv->tv_type == DISP_TV_CVBS)
884 info = cvbs_timing;
885 else if (p_tv->tv_type == DISP_VGA)
886 info = vga_timing;
887 else
888 info = ypbpr_timing;
889
890 for (i = 0; i < list_num; i++) {
891 if (info->tv_mode == tv_mode)
892 return 1;
893 info++;
894 }
895 return 0;
896 }
897
sunxi_tv_get_video_mode_info(int tv_id,struct disp_video_timings ** video_info,enum disp_tv_mode tv_mode)898 int sunxi_tv_get_video_mode_info(int tv_id,
899 struct disp_video_timings **video_info,
900 enum disp_tv_mode tv_mode)
901 {
902 struct disp_video_timings *info;
903 int ret = -1;
904 int i, list_num;
905 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
906 if (!p_tv || !video_info) {
907 TV_ERR("Null pointer!\n");
908 return 0;
909 }
910
911 TV_DBG("tv %d\n", p_tv->id);
912 info = p_tv->video_info;
913
914 list_num = tv_get_timing_list_num(p_tv);
915 for (i = 0; i < list_num; i++) {
916 mutex_lock(&p_tv->mlock);
917 if (info->tv_mode == tv_mode) {
918 *video_info = info;
919 ret = 0;
920 mutex_unlock(&p_tv->mlock);
921 break;
922 }
923 mutex_unlock(&p_tv->mlock);
924 info++;
925 }
926 return ret;
927 }
928
sunxi_tv_get_video_timing_info(int tv_id,unsigned int * num,struct disp_video_timings ** video_info)929 int sunxi_tv_get_video_timing_info(int tv_id, unsigned int *num,
930 struct disp_video_timings **video_info)
931 {
932 struct sunxi_tv *p_tv = sunxi_tv_get_tv(tv_id);
933
934 if (!p_tv || !num || !video_info) {
935 TV_ERR("Null pointer!\n");
936 return -1;
937 }
938
939 *num = tv_get_timing_list_num(p_tv);
940 *video_info = p_tv->video_info;
941 if (!*num || !*video_info) {
942 TV_ERR("Fail to get num or video_info!\n");
943 return -1;
944 }
945 return 0;
946 }
947
948 #ifdef CONFIG_AW_AXP
tv_power_enable(const char * name)949 static int tv_power_enable(const char *name)
950 {
951 struct regulator *regu = NULL;
952 int ret = -1;
953
954 if (!name) {
955 goto exit;
956 }
957
958 regu = regulator_get(NULL, name);
959 if (IS_ERR(regu)) {
960 TV_ERR("%s: some error happen, fail to get regulator %s\n",
961 __func__, name);
962 goto exit;
963 }
964
965 /* enalbe regulator */
966 ret = regulator_enable(regu);
967 if (0 != ret) {
968 TV_ERR("%s: some error happen, fail to enable regulator %s!\n",
969 __func__, name);
970 goto exit1;
971 }
972
973
974 exit1:
975 /* put regulater, when module exit */
976 regulator_put(regu);
977 exit:
978 return ret;
979 }
980
tv_power_disable(const char * name)981 static int tv_power_disable(const char *name)
982 {
983 struct regulator *regu = NULL;
984 int ret = 0;
985
986 if (!name) {
987 goto exit;
988 }
989
990 regu = regulator_get(NULL, name);
991 if (IS_ERR(regu)) {
992 TV_ERR("%s: some error happen, fail to get regulator %s\n",
993 __func__, name);
994 goto exit;
995 }
996
997 /*disalbe regulator*/
998 ret = regulator_disable(regu);
999 if (0 != ret) {
1000 TV_ERR("%s: some error happen, fail to disable regulator %s!\n",
1001 __func__, name);
1002 goto exit1;
1003 }
1004 exit1:
1005 /*put regulater, when module exit*/
1006 regulator_put(regu);
1007 exit:
1008 return ret;
1009 }
1010 #else
tv_power_enable(char * name)1011 static int tv_power_enable(char *name)
1012 {
1013 return 0;
1014 }
tv_power_disable(char * name)1015 static int tv_power_disable(char *name)
1016 {
1017 return 0;
1018 }
1019 #endif
1020
1021 #if defined(TVE_TOP_SUPPORT)
tv_top_init(struct sunxi_tv * p_tv)1022 static int tv_top_init(struct sunxi_tv *p_tv)
1023 {
1024 int ret = -1;
1025 struct platform_device *pdev = p_tv->pdev;
1026
1027 pdev->id = of_alias_get_id(pdev->dev.of_node, "tv");
1028 if (pdev->id < 0) {
1029 TV_DBG("failed to get alias id\n");
1030 return -EINVAL;
1031 }
1032
1033 p_tv->top_addr = of_iomap(pdev->dev.of_node, 0);
1034 if (IS_ERR_OR_NULL(p_tv->top_addr)) {
1035 dev_err(&pdev->dev, "unable to map tve common registers\n");
1036 ret = -EINVAL;
1037 goto err_iomap;
1038 }
1039
1040 p_tv->top_clk = of_clk_get(pdev->dev.of_node, 0);
1041 if (IS_ERR(p_tv->top_clk)) {
1042 dev_err(&pdev->dev, "fail to get clk for tve common module!\n");
1043 goto err_iomap;
1044 }
1045
1046 tve_low_set_top_reg_base(p_tv->top_addr);
1047
1048 return 0;
1049
1050 err_iomap:
1051 if (p_tv->top_addr)
1052 iounmap((char __iomem *)p_tv->top_addr);
1053 return ret;
1054 }
1055
1056 #endif
1057
tve_top_clk_enable(struct sunxi_tv * p_tv)1058 static int tve_top_clk_enable(struct sunxi_tv *p_tv)
1059 {
1060 int ret = -1;
1061
1062 if (!p_tv || !p_tv->top_clk) {
1063 TV_ERR("NULL pointer!\n");
1064 goto OUT;
1065 }
1066
1067 ret = clk_prepare_enable(p_tv->top_clk);
1068 if (ret != 0)
1069 TV_ERR("fail to enable tve's top clk!\n");
1070
1071 OUT:
1072 return ret;
1073 }
1074
tve_top_clk_disable(struct sunxi_tv * p_tv)1075 static int tve_top_clk_disable(struct sunxi_tv *p_tv)
1076 {
1077 int ret = -1;
1078
1079 if (!p_tv || !p_tv->top_clk) {
1080 TV_ERR("NULL pointer!\n");
1081 goto OUT;
1082 }
1083
1084 clk_disable(p_tv->top_clk);
1085 ret = 0;
1086 OUT:
1087 return ret;
1088 }
1089
__get_offset(struct device_node * node,int i)1090 static s32 __get_offset(struct device_node *node, int i)
1091 {
1092 char sub_key[20] = {0};
1093 s32 value = 0;
1094 int ret = 0;
1095
1096 snprintf(sub_key, sizeof(sub_key), "dac_offset%d", i);
1097 ret = of_property_read_u32(node, sub_key, (u32 *)&value);
1098 if (ret < 0) {
1099 TV_DBG("there is no tve dac(%d) offset value.\n", i);
1100 } else {
1101 /* Sysconfig can not use signed params, however,
1102 * dac_offset as a signed param which ranges from
1103 * -100 to 100, is maping sysconfig params from
1104 * 0 to 200.
1105 */
1106 if ((value > 200) || (value < 0))
1107 TV_ERR("dac offset is out of range.\n");
1108 else
1109 return value - 100;
1110 }
1111
1112 return 0;
1113 }
1114
tve_clk_init(struct sunxi_tv * p_tv)1115 static void tve_clk_init(struct sunxi_tv *p_tv)
1116 {
1117 if (!p_tv) {
1118 TV_ERR("Null pointer!\n");
1119 return;
1120 }
1121
1122 p_tv->mclk_parent = clk_get_parent(p_tv->mclk);
1123 }
1124
1125 /*TODO:handle smooth display*/
tv_init(struct sunxi_tv * p_tv)1126 static int tv_init(struct sunxi_tv *p_tv)
1127 {
1128 s32 i = 0, ret = 0;
1129 u32 cali_value = 0;
1130 char sub_key[20] = {0};
1131 unsigned int value;
1132 unsigned int interface = 0;
1133 unsigned long rate = 0;
1134 struct platform_device *pdev = NULL;
1135 #if defined(CONFIG_ARCH_SUN8IW7)
1136 unsigned int cali_default[4] = {512, 512, 512, 512};
1137 #else
1138 unsigned int cali_default[4] = {625, 625, 625, 625};
1139 #endif
1140
1141 #if defined(CONFIG_ARCH_SUN8IW7)
1142 s32 sid_turn = 0;
1143 #endif
1144 if (!p_tv) {
1145 TV_ERR("Null pointer!\n");
1146 goto OUT;
1147 }
1148
1149 pdev = p_tv->pdev;
1150 ret = of_property_read_u32(pdev->dev.of_node, "interface", &interface);
1151 if (ret < 0) {
1152 TV_ERR("get tv interface failed!\n");
1153 goto OUT;
1154 }
1155 p_tv->tv_type = interface;
1156
1157 if (p_tv->tv_type == DISP_TV_CVBS)
1158 p_tv->video_info = cvbs_timing;
1159 else if (p_tv->tv_type == DISP_VGA)
1160 p_tv->video_info = vga_timing;
1161 else
1162 p_tv->video_info = ypbpr_timing;
1163
1164 memcpy(p_tv->cali, cali_default, TVE_DAC_NUM * sizeof(unsigned int));
1165 memset(p_tv->cali_offset, 0, TVE_DAC_NUM * sizeof(int));
1166
1167 tve_top_clk_enable(p_tv);
1168 /* get mapping dac */
1169 for (i = 0; i < TVE_DAC_NUM; i++) {
1170 u32 dac_no;
1171
1172 snprintf(sub_key, sizeof(sub_key), "dac_src%d", i);
1173 ret = of_property_read_u32(pdev->dev.of_node, sub_key, &value);
1174 if (ret < 0) {
1175 TV_DBG("tve%d have no dac %d\n", p_tv->id, i);
1176 } else {
1177 dac_no = value;
1178 p_tv->dac_no[i] = value;
1179 ++p_tv->dac_num;
1180 cali_value = tve_low_get_sid(dac_no);
1181
1182 TV_DBG("cali_temp = %u\n", cali_value);
1183 /* VGA mode: 16~31 bits
1184 * CVBS & YPBPR mode: 0~15 bits
1185 * zero is not allow
1186 */
1187 if (cali_value) {
1188 if (interface == DISP_VGA)
1189 p_tv->cali[dac_no] =
1190 (cali_value >> 16) & 0xffff;
1191 else {
1192 #if defined(CONFIG_ARCH_SUN8IW7)
1193 if (cali_value & (1 << 9))
1194 sid_turn =
1195 0 + (cali_value & 0x1ff);
1196 else
1197 sid_turn =
1198 0 - (cali_value & 0x1ff);
1199
1200 sid_turn += 91;
1201
1202 if (sid_turn >= 0)
1203 sid_turn = (1 << 9) | sid_turn;
1204 else
1205 sid_turn = 0 - sid_turn;
1206 cali_value = (u32)sid_turn;
1207 #endif
1208 p_tv->cali[dac_no] = cali_value & 0xffff;
1209 }
1210 }
1211 p_tv->cali_offset[dac_no] = __get_offset(pdev->dev.of_node, i);
1212 TV_DBG("cali[%u] = %u, offset[%u] = %u\n", dac_no,
1213 p_tv->cali[dac_no], dac_no, p_tv->cali_offset[dac_no]);
1214 }
1215
1216 snprintf(sub_key, sizeof(sub_key), "dac_type%d", i);
1217 ret = of_property_read_u32(pdev->dev.of_node, sub_key, &value);
1218 if (ret < 0) {
1219 TV_DBG("tve%d have no type%d\n", p_tv->id, i);
1220 /* if do'not config type, set disabled status */
1221 p_tv->dac_type[i] = DISP_TV_DAC_SRC_NONE;
1222 } else {
1223 p_tv->dac_type[i] = value;
1224 }
1225 }
1226
1227 /* parse boot params */
1228
1229 mutex_init(&p_tv->mlock);
1230 p_tv->tv_mode = DISP_TV_MOD_PAL;
1231 ret = tve_get_pixclk(p_tv, &rate);
1232 if (ret)
1233 TV_ERR("%s:tve_get_pixclk fail!\n", __func__);
1234 ret = clk_set_rate(p_tv->mclk, rate);
1235 if (ret)
1236 TV_ERR("fail to set rate(%ld) fo tve%d's clock!\n",
1237 rate, p_tv->id);
1238
1239 tve_low_set_reg_base(p_tv->id, p_tv->base_addr);
1240 tve_clk_init(p_tv);
1241 #if !defined(CONFIG_COMMON_CLK_ENABLE_SYNCBOOT)
1242 tve_clk_enable(p_tv);
1243 #endif
1244
1245 tve_low_init(p_tv->id, &p_tv->dac_no[0], p_tv->cali,
1246 p_tv->cali_offset, p_tv->dac_type,
1247 p_tv->dac_num);
1248
1249 tve_low_dac_autocheck_enable(p_tv->id);
1250
1251 OUT:
1252 return ret;
1253 }
1254
sunxi_tv_probe(struct platform_device * pdev)1255 static int sunxi_tv_probe(struct platform_device *pdev)
1256 {
1257 int ret = -1;
1258 int index = 0;
1259 struct sunxi_tv *p_tv = NULL;
1260
1261 TV_INFO(" start\n");
1262 pdev->id = of_alias_get_id(pdev->dev.of_node, "tv");
1263 if (pdev->id < 0) {
1264 TV_ERR("failed to get alias id\n");
1265 goto OUT;
1266 }
1267
1268 if (pdev->id > MAX_TV_COUNT) {
1269 TV_ERR("alias id:%d is too big!\n", pdev->id);
1270 goto OUT;
1271 }
1272
1273 p_tv = kmalloc(sizeof(struct sunxi_tv), GFP_KERNEL | __GFP_ZERO);
1274 if (!p_tv) {
1275 TV_ERR("Malloc sunxi_tv fail!\n");
1276 goto OUT;
1277 }
1278
1279 hwtv[pdev->id] = p_tv;
1280
1281 p_tv->id = pdev->id;
1282 p_tv->pdev = pdev;
1283
1284 if (of_property_read_string(pdev->dev.of_node, "tv_power",
1285 &p_tv->p_tv_power))
1286 TV_DBG("of_property_read_string tv_power failed!\n");
1287 else
1288 tv_power_enable(p_tv->p_tv_power);
1289
1290 #if defined(TVE_TOP_SUPPORT)
1291 tv_top_init(p_tv);
1292 index = 1;
1293 #endif
1294
1295 p_tv->base_addr =
1296 of_iomap(pdev->dev.of_node, index);
1297 if (IS_ERR_OR_NULL(p_tv->base_addr)) {
1298 dev_err(&pdev->dev, "fail to get addr for tve%d!\n", pdev->id);
1299 goto FREE_TV;
1300 }
1301
1302 p_tv->mclk = of_clk_get(pdev->dev.of_node, index);
1303 if (IS_ERR_OR_NULL(p_tv->mclk)) {
1304 dev_err(&pdev->dev, "fail to get clk for tve%d's!\n", pdev->id);
1305 goto err_iomap;
1306 }
1307
1308 ret = tv_init(p_tv);
1309 if (ret)
1310 goto err_iomap;
1311
1312 tv_count++;
1313
1314 return 0;
1315
1316 err_iomap:
1317 if (p_tv->base_addr)
1318 iounmap((char __iomem *)p_tv->base_addr);
1319
1320 if (p_tv->top_addr)
1321 iounmap((char __iomem *)p_tv->top_addr);
1322
1323 FREE_TV:
1324 kfree(p_tv);
1325 OUT:
1326 return ret;
1327 }
1328
sunxi_tv_remove(struct platform_device * pdev)1329 static int sunxi_tv_remove(struct platform_device *pdev)
1330 {
1331 struct sunxi_tv *p_tv = hwtv[pdev->id];
1332
1333 if (!p_tv) {
1334 TV_ERR("Null pointer!\n");
1335 return -1;
1336 }
1337
1338 sunxi_tv_disable(pdev->id);
1339 tve_top_clk_disable(p_tv);
1340 tv_power_disable(p_tv->p_tv_power);
1341 kfree(p_tv);
1342 return 0;
1343 }
1344
1345 static const struct of_device_id sunxi_tv_match[] = {
1346 { .compatible = "allwinner,sunxi-tv", },
1347
1348 {},
1349 };
1350
1351 struct platform_driver sunxi_tv_platform_driver = {
1352 .probe = sunxi_tv_probe,
1353 .remove = sunxi_tv_remove,
1354 .driver = {
1355 .name = "tv",
1356 .owner = THIS_MODULE,
1357 .of_match_table = sunxi_tv_match,
1358 },
1359 };
1360
tv_state_show(struct device * dev,struct device_attribute * attr,char * buf)1361 static ssize_t tv_state_show(struct device *dev, struct device_attribute *attr,
1362 char *buf)
1363 {
1364 ssize_t n = 0;
1365 struct sunxi_tv *p_tv = NULL;
1366 int num_of_tv = 0, i = 0;
1367 char name[40];
1368
1369 num_of_tv = sunxi_tv_get_tv_count();
1370
1371 for (i = 0; i < num_of_tv; ++i) {
1372 p_tv = sunxi_tv_get_tv(i);
1373
1374 switch (p_tv->tv_type) {
1375 case DISP_TV_CVBS:
1376 strncpy(name, "cvbs", 40);
1377 break;
1378 case DISP_VGA:
1379 strncpy(name, "vga", 40);
1380 break;
1381 case DISP_TV_YPBPR:
1382 strncpy(name, "ypbpr", 40);
1383 break;
1384 default:
1385 strncpy(name, "unknown", 40);
1386 break;
1387 }
1388 n += sprintf(buf + n, "%s%d=%d\n", name, p_tv->id,
1389 sunxi_tv_get_connect_status(p_tv->id));
1390 }
1391
1392 return n;
1393 }
1394
1395 static DEVICE_ATTR(tv_state, 0660, tv_state_show, NULL);
1396
1397 static struct attribute *tv_attributes[] = {
1398 &dev_attr_tv_state.attr,
1399 NULL
1400 };
1401
1402 static struct attribute_group tv_attribute_group = {
1403 .name = "attr",
1404 .attrs = tv_attributes,
1405 };
1406
sunxi_tv_module_init(void)1407 int sunxi_tv_module_init(void)
1408 {
1409 int ret = -1;
1410
1411 TV_INFO(" start\n");
1412 p_tv_drv = kmalloc(sizeof(struct drv_model_info), GFP_KERNEL | __GFP_ZERO);
1413 if (!p_tv_drv) {
1414 TV_ERR("Null drv_model_info pointer\n");
1415 goto OUT;
1416 }
1417 ret = alloc_chrdev_region(&p_tv_drv->devid, 0, 1, "tv");
1418 if (ret < 0) {
1419 TV_ERR("alloc_chrdev_region failed\n");
1420 goto FREE_DRV;
1421 }
1422
1423 p_tv_drv->cdev = cdev_alloc();
1424 if (!p_tv_drv->cdev) {
1425 TV_ERR("cdev_alloc failed\n");
1426 goto FREE_DRV;
1427 }
1428
1429 cdev_init(p_tv_drv->cdev, NULL);
1430 p_tv_drv->cdev->owner = THIS_MODULE;
1431 ret = cdev_add(p_tv_drv->cdev, p_tv_drv->devid, 1);
1432 if (ret) {
1433 TV_ERR("cdev_add major number:%d failed\n",
1434 MAJOR(p_tv_drv->devid));
1435 goto FREE_DRV;
1436 }
1437
1438 p_tv_drv->sysclass = class_create(THIS_MODULE, "tv");
1439 if (IS_ERR(p_tv_drv->sysclass)) {
1440 TV_ERR("create class error\n");
1441 goto FREE_DRV;
1442 }
1443
1444 p_tv_drv->dev = device_create(p_tv_drv->sysclass, NULL, p_tv_drv->devid,
1445 NULL, "tv");
1446 if (!p_tv_drv->dev) {
1447 TV_ERR("device_create failed\n");
1448 goto FREE_DRV;
1449 }
1450
1451 tv_count = 0;
1452
1453 ret = platform_driver_register(&sunxi_tv_platform_driver);
1454 if (ret) {
1455 TV_ERR("platform_driver_register failed\n");
1456 goto FREE_DEVICE;
1457 }
1458
1459 ret = sysfs_create_group(&p_tv_drv->dev->kobj, &tv_attribute_group);
1460 if (ret < 0) {
1461 TV_ERR("sysfs_create_file fail!\n");
1462 goto UNREGISTER;
1463 }
1464
1465
1466 TV_INFO(" end\n");
1467 return ret;
1468
1469 UNREGISTER:
1470 platform_driver_unregister(&sunxi_tv_platform_driver);
1471 FREE_DEVICE:
1472 device_destroy(p_tv_drv->sysclass, p_tv_drv->devid);
1473 FREE_DRV:
1474 kfree(p_tv_drv);
1475 OUT:
1476 TV_ERR(" failed\n");
1477 return -EINVAL;
1478 }
1479
sunxi_tv_module_exit(void)1480 void sunxi_tv_module_exit(void)
1481 {
1482 TV_INFO("\n");
1483 if (p_tv_drv) {
1484 platform_driver_unregister(&sunxi_tv_platform_driver);
1485
1486 device_destroy(p_tv_drv->sysclass, p_tv_drv->devid);
1487 class_destroy(p_tv_drv->sysclass);
1488
1489 cdev_del(p_tv_drv->cdev);
1490 kfree(p_tv_drv);
1491 }
1492 }
1493