1 /*
2  * hdmi_omap4_panel.c
3  *
4  * HDMI library support functions for TI OMAP4 processors.
5  *
6  * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
7  * Authors:	Mythri P k <mythripk@ti.com>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License version 2 as published by
11  * the Free Software Foundation.
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along with
19  * this program.  If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <linux/kernel.h>
23 #include <linux/err.h>
24 #include <linux/io.h>
25 #include <linux/mutex.h>
26 #include <linux/module.h>
27 #include <plat/display.h>
28 
29 #include "dss.h"
30 
31 static struct {
32 	struct mutex hdmi_lock;
33 } hdmi;
34 
35 
hdmi_panel_probe(struct omap_dss_device * dssdev)36 static int hdmi_panel_probe(struct omap_dss_device *dssdev)
37 {
38 	DSSDBG("ENTER hdmi_panel_probe\n");
39 
40 	dssdev->panel.config = OMAP_DSS_LCD_TFT |
41 			OMAP_DSS_LCD_IVS | OMAP_DSS_LCD_IHS;
42 
43 	/*
44 	 * Initialize the timings to 640 * 480
45 	 * This is only for framebuffer update not for TV timing setting
46 	 * Setting TV timing will be done only on enable
47 	 */
48 	dssdev->panel.timings.x_res = 640;
49 	dssdev->panel.timings.y_res = 480;
50 
51 	DSSDBG("hdmi_panel_probe x_res= %d y_res = %d\n",
52 		dssdev->panel.timings.x_res,
53 		dssdev->panel.timings.y_res);
54 	return 0;
55 }
56 
hdmi_panel_remove(struct omap_dss_device * dssdev)57 static void hdmi_panel_remove(struct omap_dss_device *dssdev)
58 {
59 
60 }
61 
hdmi_panel_enable(struct omap_dss_device * dssdev)62 static int hdmi_panel_enable(struct omap_dss_device *dssdev)
63 {
64 	int r = 0;
65 	DSSDBG("ENTER hdmi_panel_enable\n");
66 
67 	mutex_lock(&hdmi.hdmi_lock);
68 
69 	if (dssdev->state != OMAP_DSS_DISPLAY_DISABLED) {
70 		r = -EINVAL;
71 		goto err;
72 	}
73 
74 	r = omapdss_hdmi_display_enable(dssdev);
75 	if (r) {
76 		DSSERR("failed to power on\n");
77 		goto err;
78 	}
79 
80 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
81 
82 err:
83 	mutex_unlock(&hdmi.hdmi_lock);
84 
85 	return r;
86 }
87 
hdmi_panel_disable(struct omap_dss_device * dssdev)88 static void hdmi_panel_disable(struct omap_dss_device *dssdev)
89 {
90 	mutex_lock(&hdmi.hdmi_lock);
91 
92 	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
93 		omapdss_hdmi_display_disable(dssdev);
94 
95 	dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
96 
97 	mutex_unlock(&hdmi.hdmi_lock);
98 }
99 
hdmi_panel_suspend(struct omap_dss_device * dssdev)100 static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
101 {
102 	int r = 0;
103 
104 	mutex_lock(&hdmi.hdmi_lock);
105 
106 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) {
107 		r = -EINVAL;
108 		goto err;
109 	}
110 
111 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
112 
113 	omapdss_hdmi_display_disable(dssdev);
114 
115 err:
116 	mutex_unlock(&hdmi.hdmi_lock);
117 
118 	return r;
119 }
120 
hdmi_panel_resume(struct omap_dss_device * dssdev)121 static int hdmi_panel_resume(struct omap_dss_device *dssdev)
122 {
123 	int r = 0;
124 
125 	mutex_lock(&hdmi.hdmi_lock);
126 
127 	if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED) {
128 		r = -EINVAL;
129 		goto err;
130 	}
131 
132 	r = omapdss_hdmi_display_enable(dssdev);
133 	if (r) {
134 		DSSERR("failed to power on\n");
135 		goto err;
136 	}
137 
138 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
139 
140 err:
141 	mutex_unlock(&hdmi.hdmi_lock);
142 
143 	return r;
144 }
145 
hdmi_get_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)146 static void hdmi_get_timings(struct omap_dss_device *dssdev,
147 			struct omap_video_timings *timings)
148 {
149 	mutex_lock(&hdmi.hdmi_lock);
150 
151 	*timings = dssdev->panel.timings;
152 
153 	mutex_unlock(&hdmi.hdmi_lock);
154 }
155 
hdmi_set_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)156 static void hdmi_set_timings(struct omap_dss_device *dssdev,
157 			struct omap_video_timings *timings)
158 {
159 	DSSDBG("hdmi_set_timings\n");
160 
161 	mutex_lock(&hdmi.hdmi_lock);
162 
163 	dssdev->panel.timings = *timings;
164 
165 	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
166 		/* turn the hdmi off and on to get new timings to use */
167 		omapdss_hdmi_display_disable(dssdev);
168 		omapdss_hdmi_display_set_timing(dssdev);
169 	}
170 
171 	mutex_unlock(&hdmi.hdmi_lock);
172 }
173 
hdmi_check_timings(struct omap_dss_device * dssdev,struct omap_video_timings * timings)174 static int hdmi_check_timings(struct omap_dss_device *dssdev,
175 			struct omap_video_timings *timings)
176 {
177 	int r = 0;
178 
179 	DSSDBG("hdmi_check_timings\n");
180 
181 	mutex_lock(&hdmi.hdmi_lock);
182 
183 	r = omapdss_hdmi_display_check_timing(dssdev, timings);
184 	if (r) {
185 		DSSERR("Timing cannot be applied\n");
186 		goto err;
187 	}
188 err:
189 	mutex_unlock(&hdmi.hdmi_lock);
190 	return r;
191 }
192 
193 static struct omap_dss_driver hdmi_driver = {
194 	.probe		= hdmi_panel_probe,
195 	.remove		= hdmi_panel_remove,
196 	.enable		= hdmi_panel_enable,
197 	.disable	= hdmi_panel_disable,
198 	.suspend	= hdmi_panel_suspend,
199 	.resume		= hdmi_panel_resume,
200 	.get_timings	= hdmi_get_timings,
201 	.set_timings	= hdmi_set_timings,
202 	.check_timings	= hdmi_check_timings,
203 	.driver			= {
204 		.name   = "hdmi_panel",
205 		.owner  = THIS_MODULE,
206 	},
207 };
208 
hdmi_panel_init(void)209 int hdmi_panel_init(void)
210 {
211 	mutex_init(&hdmi.hdmi_lock);
212 
213 	omap_dss_register_driver(&hdmi_driver);
214 
215 	return 0;
216 }
217 
hdmi_panel_exit(void)218 void hdmi_panel_exit(void)
219 {
220 	omap_dss_unregister_driver(&hdmi_driver);
221 
222 }
223