d55b8784ecfde6ddfa184a6d86f5a5d659f5b9c4
[linux-3.10.git] / drivers / video / omap2 / dss / venc_panel.c
1 /*
2  * Copyright (C) 2009 Nokia Corporation
3  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
4  *
5  * VENC panel driver
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <linux/kernel.h>
21 #include <linux/err.h>
22 #include <linux/io.h>
23 #include <linux/mutex.h>
24 #include <linux/module.h>
25
26 #include <video/omapdss.h>
27
28 #include "dss.h"
29
30 static struct {
31         struct mutex lock;
32 } venc_panel;
33
34 static ssize_t display_output_type_show(struct device *dev,
35                 struct device_attribute *attr, char *buf)
36 {
37         struct omap_dss_device *dssdev = to_dss_device(dev);
38         const char *ret;
39
40         switch (dssdev->phy.venc.type) {
41         case OMAP_DSS_VENC_TYPE_COMPOSITE:
42                 ret = "composite";
43                 break;
44         case OMAP_DSS_VENC_TYPE_SVIDEO:
45                 ret = "svideo";
46                 break;
47         default:
48                 return -EINVAL;
49         }
50
51         return snprintf(buf, PAGE_SIZE, "%s\n", ret);
52 }
53
54 static ssize_t display_output_type_store(struct device *dev,
55                 struct device_attribute *attr, const char *buf, size_t size)
56 {
57         struct omap_dss_device *dssdev = to_dss_device(dev);
58         enum omap_dss_venc_type new_type;
59
60         if (sysfs_streq("composite", buf))
61                 new_type = OMAP_DSS_VENC_TYPE_COMPOSITE;
62         else if (sysfs_streq("svideo", buf))
63                 new_type = OMAP_DSS_VENC_TYPE_SVIDEO;
64         else
65                 return -EINVAL;
66
67         mutex_lock(&venc_panel.lock);
68
69         if (dssdev->phy.venc.type != new_type) {
70                 dssdev->phy.venc.type = new_type;
71                 omapdss_venc_set_type(dssdev, new_type);
72                 if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
73                         omapdss_venc_display_disable(dssdev);
74                         omapdss_venc_display_enable(dssdev);
75                 }
76         }
77
78         mutex_unlock(&venc_panel.lock);
79
80         return size;
81 }
82
83 static DEVICE_ATTR(output_type, S_IRUGO | S_IWUSR,
84                 display_output_type_show, display_output_type_store);
85
86 static int venc_panel_probe(struct omap_dss_device *dssdev)
87 {
88         /* set default timings to PAL */
89         const struct omap_video_timings default_timings = {
90                 .x_res          = 720,
91                 .y_res          = 574,
92                 .pixel_clock    = 13500,
93                 .hsw            = 64,
94                 .hfp            = 12,
95                 .hbp            = 68,
96                 .vsw            = 5,
97                 .vfp            = 5,
98                 .vbp            = 41,
99
100                 .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
101                 .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
102
103                 .interlace      = true,
104         };
105
106         mutex_init(&venc_panel.lock);
107
108         dssdev->panel.timings = default_timings;
109
110         return device_create_file(&dssdev->dev, &dev_attr_output_type);
111 }
112
113 static void venc_panel_remove(struct omap_dss_device *dssdev)
114 {
115         device_remove_file(&dssdev->dev, &dev_attr_output_type);
116 }
117
118 static int venc_panel_enable(struct omap_dss_device *dssdev)
119 {
120         int r;
121
122         dev_dbg(&dssdev->dev, "venc_panel_enable\n");
123
124         mutex_lock(&venc_panel.lock);
125
126         if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
127                 r = -EINVAL;
128                 goto err;
129         }
130
131         omapdss_venc_set_timings(dssdev, &dssdev->panel.timings);
132         omapdss_venc_set_type(dssdev, dssdev->phy.venc.type);
133         omapdss_venc_invert_vid_out_polarity(dssdev,
134                 dssdev->phy.venc.invert_polarity);
135
136         r = omapdss_venc_display_enable(dssdev);
137         if (r)
138                 goto err;
139
140         dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
141
142         mutex_unlock(&venc_panel.lock);
143
144         return 0;
145 err:
146         mutex_unlock(&venc_panel.lock);
147
148         return r;
149 }
150
151 static void venc_panel_disable(struct omap_dss_device *dssdev)
152 {
153         dev_dbg(&dssdev->dev, "venc_panel_disable\n");
154
155         mutex_lock(&venc_panel.lock);
156
157         if (dssdev->state == OMAP_DSS_DISPLAY_DISABLED)
158                 goto end;
159
160         if (dssdev->state == OMAP_DSS_DISPLAY_SUSPENDED) {
161                 /* suspended is the same as disabled with venc */
162                 dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
163                 goto end;
164         }
165
166         omapdss_venc_display_disable(dssdev);
167
168         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
169 end:
170         mutex_unlock(&venc_panel.lock);
171 }
172
173 static int venc_panel_suspend(struct omap_dss_device *dssdev)
174 {
175         venc_panel_disable(dssdev);
176         return 0;
177 }
178
179 static int venc_panel_resume(struct omap_dss_device *dssdev)
180 {
181         return venc_panel_enable(dssdev);
182 }
183
184 static void venc_panel_set_timings(struct omap_dss_device *dssdev,
185                 struct omap_video_timings *timings)
186 {
187         dev_dbg(&dssdev->dev, "venc_panel_set_timings\n");
188
189         mutex_lock(&venc_panel.lock);
190
191         omapdss_venc_set_timings(dssdev, timings);
192         dssdev->panel.timings = *timings;
193
194         mutex_unlock(&venc_panel.lock);
195 }
196
197 static int venc_panel_check_timings(struct omap_dss_device *dssdev,
198                 struct omap_video_timings *timings)
199 {
200         dev_dbg(&dssdev->dev, "venc_panel_check_timings\n");
201
202         return omapdss_venc_check_timings(dssdev, timings);
203 }
204
205 static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
206 {
207         dev_dbg(&dssdev->dev, "venc_panel_get_wss\n");
208
209         return omapdss_venc_get_wss(dssdev);
210 }
211
212 static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
213 {
214         dev_dbg(&dssdev->dev, "venc_panel_set_wss\n");
215
216         return omapdss_venc_set_wss(dssdev, wss);
217 }
218
219 static struct omap_dss_driver venc_driver = {
220         .probe          = venc_panel_probe,
221         .remove         = venc_panel_remove,
222
223         .enable         = venc_panel_enable,
224         .disable        = venc_panel_disable,
225         .suspend        = venc_panel_suspend,
226         .resume         = venc_panel_resume,
227
228         .get_resolution = omapdss_default_get_resolution,
229         .get_recommended_bpp = omapdss_default_get_recommended_bpp,
230
231         .set_timings    = venc_panel_set_timings,
232         .check_timings  = venc_panel_check_timings,
233
234         .get_wss        = venc_panel_get_wss,
235         .set_wss        = venc_panel_set_wss,
236
237         .driver         = {
238                 .name   = "venc",
239                 .owner  = THIS_MODULE,
240         },
241 };
242
243 int venc_panel_init(void)
244 {
245         return omap_dss_register_driver(&venc_driver);
246 }
247
248 void venc_panel_exit(void)
249 {
250         omap_dss_unregister_driver(&venc_driver);
251 }