Merge remote-tracking branches 'spi/fix/qup' and 'spi/fix/topcliff-pch' into spi...
[cascardo/linux.git] / drivers / video / fbdev / 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                 .pixelclock     = 13500000,
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         omapdss_venc_display_disable(dssdev);
161
162         dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
163 end:
164         mutex_unlock(&venc_panel.lock);
165 }
166
167 static void venc_panel_set_timings(struct omap_dss_device *dssdev,
168                 struct omap_video_timings *timings)
169 {
170         dev_dbg(dssdev->dev, "venc_panel_set_timings\n");
171
172         mutex_lock(&venc_panel.lock);
173
174         omapdss_venc_set_timings(dssdev, timings);
175         dssdev->panel.timings = *timings;
176
177         mutex_unlock(&venc_panel.lock);
178 }
179
180 static int venc_panel_check_timings(struct omap_dss_device *dssdev,
181                 struct omap_video_timings *timings)
182 {
183         dev_dbg(dssdev->dev, "venc_panel_check_timings\n");
184
185         return omapdss_venc_check_timings(dssdev, timings);
186 }
187
188 static u32 venc_panel_get_wss(struct omap_dss_device *dssdev)
189 {
190         dev_dbg(dssdev->dev, "venc_panel_get_wss\n");
191
192         return omapdss_venc_get_wss(dssdev);
193 }
194
195 static int venc_panel_set_wss(struct omap_dss_device *dssdev, u32 wss)
196 {
197         dev_dbg(dssdev->dev, "venc_panel_set_wss\n");
198
199         return omapdss_venc_set_wss(dssdev, wss);
200 }
201
202 static struct omap_dss_driver venc_driver = {
203         .probe          = venc_panel_probe,
204         .remove         = venc_panel_remove,
205
206         .enable         = venc_panel_enable,
207         .disable        = venc_panel_disable,
208
209         .get_resolution = omapdss_default_get_resolution,
210         .get_recommended_bpp = omapdss_default_get_recommended_bpp,
211
212         .set_timings    = venc_panel_set_timings,
213         .check_timings  = venc_panel_check_timings,
214
215         .get_wss        = venc_panel_get_wss,
216         .set_wss        = venc_panel_set_wss,
217
218         .driver         = {
219                 .name   = "venc",
220                 .owner  = THIS_MODULE,
221         },
222 };
223
224 int venc_panel_init(void)
225 {
226         return omap_dss_register_driver(&venc_driver);
227 }
228
229 void venc_panel_exit(void)
230 {
231         omap_dss_unregister_driver(&venc_driver);
232 }