Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(30)

Side by Side Diff: drivers/media/video/samsung/tv20/s5p_tv_base.c

Issue 2036011: V4L/DVB : Add S5PV210 TV out driver support (Closed) Base URL: swsolcc@12.23.106.100:kernel-samsung.git
Patch Set: Created 10 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /* linux/drivers/media/video/samsung/tv20/s5p_tv_base.c
2 *
3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
4 * http://www.samsung.com/
5 *
6 * S5PV210 - Entry file for Samsung TVOut driver
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License version 2 as
10 * published by the Free Software Foundation.
11 */
12
13 #include <linux/init.h>
14 #include <linux/module.h>
15 #include <linux/kernel.h>
16 #include <linux/string.h>
17 #include <linux/fs.h>
18 #include <linux/init.h>
19 #include <linux/mm.h>
20 #include <linux/interrupt.h>
21 #include <linux/miscdevice.h>
22 #include <linux/platform_device.h>
23 #include <linux/workqueue.h>
24 #include <linux/wait.h>
25 #include <linux/ioctl.h>
26 #include <linux/device.h>
27 #include <linux/clk.h>
28 #include <linux/i2c.h>
29 #include <linux/delay.h>
30 #include <linux/irq.h>
31
32 #include <media/v4l2-common.h>
33 #include <media/v4l2-ioctl.h>
34 #include <mach/map.h>
35
36 #include <mach/gpio.h>
37 #include <plat/gpio-cfg.h>
38
39 #include <linux/io.h>
40 #include <linux/uaccess.h>
41
42 #ifdef CONFIG_S5PV210_PM
43 #include <mach/pd.h>
44 #endif
45
46 #include "s5p_tv.h"
47
48 #ifdef CONFIG_TVOUT_DBG
49 #define S5P_TV_BASE_DEBUG 1
50 #endif
51
52 #ifdef S5P_TV_BASE_DEBUG
53 #define BASEPRINTK(fmt, args...) \
54 printk(KERN_INFO "[TVBASE] %s: " fmt, __func__ , ## args)
55 #else
56 #define BASEPRINTK(fmt, args...)
57 #endif
58
59
60 #define TVOUT_CLK_INIT(dev, clk, name)
61
62 #define TVOUT_IRQ_INIT(x, ret, dev, num, jump, ftn, m_name) \
63 do { \
64 x = platform_get_irq(dev, num); \
65 if (x < 0) { \
66 printk(KERN_ERR \
67 "failed to get %s irq resource\n", m_name); \
68 ret = -ENOENT; \
69 goto jump; \
70 } \
71 ret = request_irq(x, ftn, IRQF_DISABLED, dev->name, dev); \
72 if (ret != 0) { \
73 printk(KERN_ERR \
74 "failed to install %s irq (%d)\n", m_name, ret); \
75 goto jump; \
76 } \
77 } while (0)
78
79
80 static struct mutex *mutex_for_fo;
81
82
83 struct s5p_tv_status s5ptv_status;
84 struct s5p_tv_vo s5ptv_overlay[2];
85 wait_queue_head_t s5ptv_wq;
86
87 #ifdef I2C_BASE
88 static struct mutex *mutex_for_i2c;
89 static struct work_struct ws_hpd;
90 spinlock_t slock_hpd;
91
92 static struct i2c_driver hdcp_i2c_driver;
93 static bool hdcp_i2c_drv_state;
94
95 const static u16 ignore[] = {I2C_CLIENT_END};
96 const static u16 normal_addr[] = {(S5P_HDCP_I2C_ADDR >> 1), I2C_CLIENT_END};
97 const static u16 *forces[] = {NULL};
98
99 static struct i2c_client_address_data addr_data = {
100 .normal_i2c = normal_addr,
101 .probe = ignore,
102 .ignore = ignore,
103 .forces = forces,
104 };
105
106 /*
107 * i2c client drv. - register client drv
108 */
109 static int hdcp_i2c_attach(struct i2c_adapter *adap, int addr, int kind)
110 {
111
112 struct i2c_client *c;
113
114 c = kzalloc(sizeof(*c), GFP_KERNEL);
115
116 if (!c)
117 return -ENOMEM;
118
119 strcpy(c->name, "s5p_ddc_client");
120
121 c->addr = addr;
122
123 c->adapter = adap;
124
125 c->driver = &hdcp_i2c_driver;
126
127 s5ptv_status.hdcp_i2c_client = c;
128
129 dev_info(&adap->dev, "s5p_ddc_client attached "
130 "into s5p_ddc_port successfully\n");
131
132 return i2c_attach_client(c);
133 }
134
135 static int hdcp_i2c_attach_adapter(struct i2c_adapter *adap)
136 {
137 int ret = 0;
138
139 ret = i2c_probe(adap, &addr_data, hdcp_i2c_attach);
140
141 if (ret) {
142 dev_err(&adap->dev,
143 "failed to attach s5p_hdcp_port driver\n");
144 ret = -ENODEV;
145 }
146
147 return ret;
148 }
149
150 static int hdcp_i2c_detach(struct i2c_client *client)
151 {
152 dev_info(&client->adapter->dev, "s5p_ddc_client detached "
153 "from s5p_ddc_port successfully\n");
154
155 i2c_detach_client(client);
156
157 return 0;
158 }
159
160 static struct i2c_driver hdcp_i2c_driver = {
161 .driver = {
162 .name = "s5p_ddc_port",
163 },
164 .id = I2C_DRIVERID_S5P_HDCP,
165 .attach_adapter = hdcp_i2c_attach_adapter,
166 .detach_client = hdcp_i2c_detach,
167 };
168
169 static void set_ddc_port(void)
170 {
171 mutex_lock(mutex_for_i2c);
172
173 if (s5ptv_status.hpd_status) {
174
175 if (!hdcp_i2c_drv_state)
176 /* cable : plugged, drv : unregistered */
177 if (i2c_add_driver(&hdcp_i2c_driver))
178 printk(KERN_INFO "HDCP port add failed\n");
179
180 /* changed drv. status */
181 hdcp_i2c_drv_state = true;
182
183
184 /* cable inserted -> removed */
185 tv_set_hpd_detection(true, s5ptv_status.hdcp_en,
186 s5ptv_status.hdcp_i2c_client);
187
188 } else {
189
190 if (hdcp_i2c_drv_state)
191 /* cable : unplugged, drv : registered */
192 i2c_del_driver(&hdcp_i2c_driver);
193
194 /* changed drv. status */
195 hdcp_i2c_drv_state = false;
196
197 /* cable removed -> inserted */
198 tv_set_hpd_detection(false, s5ptv_status.hdcp_en,
199 s5ptv_status.hdcp_i2c_client);
200 }
201
202 mutex_unlock(mutex_for_i2c);
203 }
204 #endif
205
206 int tv_phy_power(bool on)
207 {
208 if (on) {
209 /* on */
210 clk_enable(s5ptv_status.i2c_phy_clk);
211
212 tv_hdmi_phy_power(true);
213
214 } else {
215 /*
216 * for preventing hdmi hang up when restart
217 * switch to internal clk - SCLK_DAC, SCLK_PIXEL
218 */
219 tv_clk_change_internal();
220
221 tv_hdmi_phy_power(false);
222
223 clk_disable(s5ptv_status.i2c_phy_clk);
224 }
225
226 return 0;
227 }
228
229
230 int s5p_tv_clk_gate(bool on)
231 {
232 if (on) {
233 #ifdef CONFIG_S5PV210_PM
234 if (s5pv210_pd_enable("vp_pd") < 0) {
235 printk(KERN_ERR "[Err]Power is not on for VP\n");
236 goto err_pm;
237 }
238 #endif
239 clk_enable(s5ptv_status.vp_clk);
240 #ifdef CONFIG_S5PV210_PM
241 if (s5pv210_pd_enable("mixer_pd") < 0) {
242 printk(KERN_ERR "[Err]Power is not on for mixer\n");
243 goto err_pm;
244 }
245 #endif
246 clk_enable(s5ptv_status.mixer_clk);
247 #ifdef CONFIG_S5PV210_PM
248 if (s5pv210_pd_enable("tv_enc_pd") < 0) {
249 printk(KERN_ERR "[Err]Power is not on for TV ENC\n");
250 goto err_pm;
251 }
252 #endif
253 clk_enable(s5ptv_status.tvenc_clk);
254 #ifdef CONFIG_S5PV210_PM
255 if (s5pv210_pd_enable("hdmi_pd") < 0) {
256 printk(KERN_ERR "[Err]Power is not on for HDMI\n");
257 goto err_pm;
258 }
259 #endif
260 clk_enable(s5ptv_status.hdmi_clk);
261
262 } else {
263
264 /* off */
265 clk_disable(s5ptv_status.vp_clk);
266 #ifdef CONFIG_S5PV210_PM
267 if (s5pv210_pd_disable("vp_pd") < 0) {
268 printk(KERN_ERR "[Err]Power is not off for VP\n");
269 goto err_pm;
270 }
271 #endif
272 clk_disable(s5ptv_status.mixer_clk);
273 #ifdef CONFIG_S5PV210_PM
274 if (0 != s5pv210_pd_disable("mixer_pd")) {
275 printk(KERN_ERR "[Err]Power is not off for mixer\n");
276 goto err_pm;
277 }
278 #endif
279 clk_disable(s5ptv_status.tvenc_clk);
280 #ifdef CONFIG_S5PV210_PM
281 if (s5pv210_pd_disable("tv_enc_pd") < 0) {
282 printk(KERN_ERR "[Err]Power is not off for TV ENC\n");
283 goto err_pm;
284 }
285 #endif
286 clk_disable(s5ptv_status.hdmi_clk);
287 #ifdef CONFIG_S5PV210_PM
288 if (s5pv210_pd_disable("hdmi_pd") < 0) {
289 printk(KERN_ERR "[Err]Power is not off for HDMI\n");
290 goto err_pm;
291 }
292 #endif
293 }
294
295 return 0;
296 #ifdef CONFIG_S5PV210_PM
297 err_pm:
298 return -1;
299 #endif
300 }
301
302 static int __devinit tv_clk_get(struct platform_device *pdev,
303 struct s5p_tv_status *ctrl)
304 {
305 /* tvenc clk */
306 ctrl->tvenc_clk = clk_get(&pdev->dev, "tvenc");
307
308 if (IS_ERR(ctrl->tvenc_clk)) {
309 printk(KERN_ERR "failed to find %s clock source\n", "tvenc");
310 return -ENOENT;
311 }
312
313 /* vp clk */
314 ctrl->vp_clk = clk_get(&pdev->dev, "vp");
315
316 if (IS_ERR(ctrl->vp_clk)) {
317 printk(KERN_ERR "failed to find %s clock source\n", "vp");
318 return -ENOENT;
319 }
320
321 /* mixer clk */
322 ctrl->mixer_clk = clk_get(&pdev->dev, "mixer");
323
324 if (IS_ERR(ctrl->mixer_clk)) {
325 printk(KERN_ERR "failed to find %s clock source\n", "mixer");
326 return -ENOENT;
327 }
328
329 /* hdmi clk */
330 ctrl->hdmi_clk = clk_get(&pdev->dev, "hdmi");
331
332 if (IS_ERR(ctrl->hdmi_clk)) {
333 printk(KERN_ERR "failed to find %s clock source\n", "hdmi");
334 return -ENOENT;
335 }
336
337 /* i2c-hdmiphy clk */
338 ctrl->i2c_phy_clk = clk_get(&pdev->dev, "i2c-hdmiphy");
339
340 if (IS_ERR(ctrl->i2c_phy_clk)) {
341 printk(KERN_ERR
342 "failed to find %s clock source\n", "i2c-hdmiphy");
343 return -ENOENT;
344 }
345
346 return 0;
347 }
348
349 /*
350 * ftn for irq
351 */
352 static irqreturn_t s5p_tvenc_irq(int irq, void *dev_id)
353 {
354 return IRQ_HANDLED;
355 }
356
357 static int s5p_tv_open(struct file *file)
358 {
359 /*
360 * for first open
361 * when boot up time this parameter is set.
362 */
363
364 if (s5ptv_status.tvout_output_enable)
365 tv_if_stop();
366
367 return 0;
368 }
369
370 static int s5p_tv_release(struct file *file)
371 {
372 s5ptv_status.hdcp_en = false;
373
374 if (s5ptv_status.tvout_output_enable)
375 tv_if_stop();
376
377 return 0;
378 }
379
380 static int s5p_tv_vid_open(struct file *file)
381 {
382 int ret = 0;
383
384 mutex_lock(mutex_for_fo);
385
386 if (s5ptv_status.vp_layer_enable) {
387 printk(KERN_ERR "video layer. already used !!\n");
388 ret = -EBUSY;
389 }
390
391 mutex_unlock(mutex_for_fo);
392 return ret;
393 }
394
395 static int s5p_tv_vid_release(struct file *file)
396 {
397 s5ptv_status.vp_layer_enable = false;
398
399 tv_vlayer_stop();
400
401 return 0;
402 }
403
404 int s5ptvfb_alloc_framebuffer(void)
405 {
406 int ret;
407
408 /* alloc for each framebuffer */
409 s5ptv_status.fb = framebuffer_alloc(sizeof(struct s5ptvfb_window),
410 s5ptv_status.dev_fb);
411 if (!s5ptv_status.fb) {
412 dev_err(s5ptv_status.dev_fb, "not enough memory\n");
413 ret = -ENOMEM;
414 goto err_alloc_fb;
415 }
416
417 /* Initializing framebuffer struct. */
418 memset(s5ptv_status.fb, 0, sizeof(struct s5ptvfb_window));
419
420 /* Changing frame number 0 into 5 for TV out */
421 ret = s5ptvfb_init_fbinfo(5);
422 if (ret) {
423 dev_err(s5ptv_status.dev_fb,
424 "failed to allocate memory for fb for tv\n");
425 ret = -ENOMEM;
426 goto err_alloc_fb;
427 }
428
429 return 0;
430
431 err_alloc_fb:
432 if (s5ptv_status.fb)
433 framebuffer_release(s5ptv_status.fb);
434
435 kfree(s5ptv_status.fb);
436
437 return ret;
438 }
439
440 int s5ptvfb_free_framebuffer(void)
441 {
442 if (s5ptv_status.fb)
443 framebuffer_release(s5ptv_status.fb);
444
445 return 0;
446 }
447
448 int s5ptvfb_register_framebuffer(void)
449 {
450 int ret;
451
452 ret = register_framebuffer(s5ptv_status.fb);
453 if (ret) {
454 dev_err(s5ptv_status.dev_fb, "failed to register "
455 "framebuffer device\n");
456 return -EINVAL;
457 }
458 return 0;
459 }
460
461 int s5ptvfb_unregister_framebuffer(void)
462 {
463 if (s5ptv_status.fb)
464 unregister_framebuffer(s5ptv_status.fb);
465
466 return 0;
467 }
468
469 /*
470 * struct for video
471 */
472 static struct v4l2_file_operations s5p_tv_fops = {
473 .owner = THIS_MODULE,
474 .open = s5p_tv_open,
475 .ioctl = s5p_tv_ioctl,
476 .release = s5p_tv_release
477 };
478 static struct v4l2_file_operations s5p_tv_vid_fops = {
479 .owner = THIS_MODULE,
480 .open = s5p_tv_vid_open,
481 .ioctl = s5p_tv_vid_ioctl,
482 .release = s5p_tv_vid_release
483 };
484
485
486 void s5p_tv_vdev_release(struct video_device *vdev)
487 {
488 kfree(vdev);
489 }
490
491 struct video_device s5p_tvout[] = {
492 [0] = {
493 .name = "S5PV210 TVOUT ctrl",
494 .fops = &s5p_tv_fops,
495 .ioctl_ops = &s5p_tv_v4l2_ops,
496 .release = s5p_tv_vdev_release,
497 .minor = TVOUT_MINOR_TVOUT,
498 .tvnorms = V4L2_STD_ALL_HD,
499 },
500 [1] = {
501 .name = "S5PV210 TVOUT for Video",
502 .fops = &s5p_tv_vid_fops,
503 .ioctl_ops = &s5p_tv_v4l2_vid_ops,
504 .release = s5p_tv_vdev_release,
505 .minor = TVOUT_MINOR_VID,
506 .tvnorms = V4L2_STD_ALL_HD,
507 },
508 };
509
510 void s5p_tv_kobject_uevent(struct work_struct *data)
511 {
512 int hpd_state = s5p_hpd_get_state();
513
514 if (hpd_state) {
515 printk(KERN_ERR "Event] Send UEvent = %d\n", hpd_state);
516 kobject_uevent(&(s5p_tvout[0].dev.kobj), KOBJ_ADD);
517 kobject_uevent(&(s5p_tvout[1].dev.kobj), KOBJ_ADD);
518 } else {
519 printk(KERN_ERR "Event] Send UEvent = %d\n", hpd_state);
520 kobject_uevent(&(s5p_tvout[0].dev.kobj), KOBJ_REMOVE);
521 kobject_uevent(&(s5p_tvout[1].dev.kobj), KOBJ_REMOVE);
522 }
523
524 }
525
526
527
528 #define S5P_TVMAX_CTRLS ARRAY_SIZE(s5p_tvout)
529
530 static int __devinit s5p_tv_probe(struct platform_device *pdev)
531 {
532 int irq_num;
533 int ret;
534 int i;
535
536 s5ptv_status.dev_fb = &pdev->dev;
537
538 tv_sdout_probe(pdev, 0);
539 tv_vp_probe(pdev, 1);
540 tv_mixer_probe(pdev, 2);
541
542 tv_hdmi_probe(pdev, 3, 4);
543
544 tv_hdcp_init();
545
546 tv_clk_get(pdev, &s5ptv_status);
547
548 #ifdef FIX_27M_UNSTABLE_ISSUE /* for smdkc100 pop */
549 writel(0x1, S5PC1XX_GPA0_BASE + 0x56c);
550 #endif
551
552 #ifdef I2C_BASE
553 /* for dev_dbg err. */
554 spin_lock_init(&slock_hpd);
555
556 /* for bh */
557 INIT_WORK(&ws_hpd, (void *)set_ddc_port);
558 #endif
559 /* interrupt */
560 /* Changing interrupt mode into SHARED */
561 irq_num = platform_get_irq(pdev, 0);
562 if (irq_num < 0) {
563 printk(KERN_ERR "failed to get %s irq resource\n", "mixer");
564 ret = -ENOENT;
565 goto out;
566 }
567
568 ret = request_irq(irq_num, tv_mixer_irq,
569 IRQF_SHARED, pdev->name, pdev);
570 if (ret != 0) {
571 printk(KERN_ERR "failed to install %s irq (%d)\n", "mixer",
572 ret);
573 goto out;
574 }
575
576 TVOUT_IRQ_INIT(irq_num, ret, pdev, 1, out_hdmi_irq,
577 tv_hdmi_irq , "hdmi");
578 TVOUT_IRQ_INIT(irq_num, ret, pdev, 2, out_tvenc_irq,
579 s5p_tvenc_irq, "tvenc");
580
581 set_irq_type(IRQ_EINT5, IRQ_TYPE_LEVEL_LOW);
582
583 /* v4l2 video device registration */
584 for (i = 0; i < S5P_TVMAX_CTRLS; i++) {
585 s5ptv_status.video_dev[i] = &s5p_tvout[i];
586
587 if (video_register_device(s5ptv_status.video_dev[i],
588 VFL_TYPE_GRABBER, s5p_tvout[i].minor) != 0) {
589
590 dev_err(&pdev->dev,
591 "Couldn't register tvout driver.\n");
592 return 0;
593 }
594 }
595
596 /* for default start up */
597 tv_if_init_param();
598
599 s5ptv_status.tvout_param.disp_mode = TVOUT_720P_60;
600 s5ptv_status.tvout_param.out_mode = TVOUT_OUTPUT_HDMI_RGB;
601
602 mutex_init(&s5ptv_status.fb_lock);
603
604 s5ptvfb_set_lcd_info(&s5ptv_status);
605
606 /* prepare memory */
607 if (s5ptvfb_alloc_framebuffer())
608 goto err_alloc;
609
610 if (s5ptvfb_register_framebuffer())
611 goto err_alloc;
612
613 mutex_for_fo =
614 kmalloc(sizeof(struct mutex), GFP_KERNEL);
615
616 if (mutex_for_fo == NULL) {
617 dev_err(&pdev->dev,
618 "failed to create mutex handle\n");
619 goto out;
620 }
621
622 #ifdef I2C_BASE
623 mutex_for_i2c =
624 kmalloc(sizeof(struct mutex), GFP_KERNEL);
625
626 if (mutex_for_i2c == NULL) {
627 dev_err(&pdev->dev,
628 "failed to create mutex handle\n");
629 goto out;
630 }
631 mutex_init(mutex_for_i2c);
632 #endif
633 mutex_init(mutex_for_fo);
634
635 return 0;
636
637 err_alloc:
638
639 out_tvenc_irq:
640 free_irq(IRQ_HDMI, pdev);
641
642 out_hdmi_irq:
643 free_irq(IRQ_MIXER, pdev);
644
645 out:
646 printk(KERN_ERR "not found (%d). \n", ret);
647
648 return ret;
649 }
650
651 static int s5p_tv_remove(struct platform_device *pdev)
652 {
653 tv_hdmi_release(pdev);
654 tv_sdout_release(pdev);
655 tv_mixer_release(pdev);
656 tv_vp_release(pdev);
657
658 #ifdef I2C_BASE
659 i2c_del_driver(&hdcp_i2c_driver);
660 #endif
661 clk_disable(s5ptv_status.tvenc_clk);
662 clk_disable(s5ptv_status.vp_clk);
663 clk_disable(s5ptv_status.mixer_clk);
664 clk_disable(s5ptv_status.hdmi_clk);
665 clk_disable(s5ptv_status.sclk_hdmi);
666 clk_disable(s5ptv_status.sclk_mixer);
667 clk_disable(s5ptv_status.sclk_tv);
668
669 clk_put(s5ptv_status.tvenc_clk);
670 clk_put(s5ptv_status.vp_clk);
671 clk_put(s5ptv_status.mixer_clk);
672 clk_put(s5ptv_status.hdmi_clk);
673 clk_put(s5ptv_status.sclk_hdmi);
674 clk_put(s5ptv_status.sclk_mixer);
675 clk_put(s5ptv_status.sclk_tv);
676
677 free_irq(IRQ_MIXER, pdev);
678 free_irq(IRQ_HDMI, pdev);
679 free_irq(IRQ_TVENC, pdev);
680 free_irq(IRQ_EINT5, pdev);
681
682 mutex_destroy(mutex_for_fo);
683 #ifdef I2C_BASE
684 mutex_destroy(mutex_for_i2c);
685 #endif
686
687 s5ptvfb_unregister_framebuffer();
688 s5ptvfb_free_framebuffer();
689 return 0;
690 }
691
692
693 #ifdef CONFIG_PM
694 int s5p_tv_suspend(struct platform_device *dev, pm_message_t state)
695 {
696 /* video layer stop */
697 if (s5ptv_status.vp_layer_enable) {
698 tv_vlayer_stop();
699 s5ptv_status.vp_layer_enable = true;
700
701 }
702
703 /* grp0 layer stop */
704 if (s5ptv_status.grp_layer_enable[0]) {
705 tv_grp_stop(VM_GPR0_LAYER);
706 s5ptv_status.grp_layer_enable[VM_GPR0_LAYER] = true;
707 }
708
709 /* grp1 layer stop */
710 if (s5ptv_status.grp_layer_enable[1]) {
711 tv_grp_stop(VM_GPR1_LAYER);
712 s5ptv_status.grp_layer_enable[VM_GPR0_LAYER] = true;
713 }
714
715 /* tv off */
716 if (s5ptv_status.tvout_output_enable) {
717 tv_if_stop();
718 s5ptv_status.tvout_output_enable = true;
719 s5ptv_status.tvout_param_available = true;
720
721 /* clk & power off */
722 if (s5p_tv_clk_gate(false) < 0) {
723 printk(KERN_ERR "[Error]Cannot suspend\n");
724 return -1;
725 }
726 tv_phy_power(false);
727
728 }
729
730 return 0;
731 }
732
733 int s5p_tv_resume(struct platform_device *dev)
734 {
735 /* tv on */
736 if (s5ptv_status.tvout_output_enable) {
737
738 /* clk & power on */
739 if (s5p_tv_clk_gate(true) < 0) {
740 printk(KERN_ERR "[Error]Cannot resume\n");
741 return -1;
742 }
743 tv_phy_power(true);
744
745 tv_if_start();
746 }
747
748 /* video layer start */
749 if (s5ptv_status.vp_layer_enable)
750 tv_vlayer_start();
751
752 /* grp0 layer start */
753 if (s5ptv_status.grp_layer_enable[0])
754 tv_grp_start(VM_GPR0_LAYER);
755
756 /* grp1 layer start */
757 if (s5ptv_status.grp_layer_enable[1])
758 tv_grp_start(VM_GPR1_LAYER);
759
760 s5ptvfb_display_on(&s5ptv_status);
761 s5ptvfb_set_par(s5ptv_status.fb);
762
763 return 0;
764 }
765 #else
766 #define s5p_tv_suspend NULL
767 #define s5p_tv_resume NULL
768 #endif
769
770 static struct platform_driver s5p_tv_driver = {
771 .probe = s5p_tv_probe,
772 .remove = s5p_tv_remove,
773 .suspend = s5p_tv_suspend,
774 .resume = s5p_tv_resume,
775 .driver = {
776 .name = "s5p-tvout",
777 .owner = THIS_MODULE,
778 },
779 };
780
781 static char banner[] __initdata =
782 KERN_INFO "S5V210 TVOUT Driver, (c) 2010 Samsung Electronics\n";
783
784 int __init s5p_tv_init(void)
785 {
786 int ret;
787
788 printk(banner);
789
790 ret = platform_driver_register(&s5p_tv_driver);
791
792 if (ret) {
793 printk(KERN_ERR "Platform Device Register Failed %d\n", ret);
794 return -1;
795 }
796
797 return 0;
798 }
799
800 static void __exit s5p_tv_exit(void)
801 {
802 platform_driver_unregister(&s5p_tv_driver);
803 }
804
805 late_initcall(s5p_tv_init);
806 module_exit(s5p_tv_exit);
807
808 MODULE_AUTHOR("SangPil Moon");
809 MODULE_DESCRIPTION("S5V210 TVOUT driver");
810 MODULE_LICENSE("GPL");
OLDNEW
« no previous file with comments | « drivers/media/video/samsung/tv20/s5p_tv.h ('k') | drivers/media/video/samsung/tv20/s5p_tv_v4l2.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698