2 * linux/drivers/video/omap2/dss/sdi.c
4 * Copyright (C) 2009 Nokia Corporation
5 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
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.
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
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/>.
20 #define DSS_SUBSYS_NAME "SDI"
22 #include <linux/kernel.h>
23 #include <linux/clk.h>
24 #include <linux/delay.h>
25 #include <linux/err.h>
27 #include <plat/display.h>
35 static void sdi_basic_init(void)
37 dispc_set_parallel_interface_mode(OMAP_DSS_PARALLELMODE_BYPASS
);
39 dispc_set_lcd_display_type(OMAP_DSS_LCD_DISPLAY_TFT
);
40 dispc_set_tft_data_lines(24);
41 dispc_lcd_enable_signal_polarity(1);
44 static int sdi_display_enable(struct omap_dss_device
*dssdev
)
46 struct omap_video_timings
*t
= &dssdev
->panel
.timings
;
47 struct dss_clock_info dss_cinfo
;
48 struct dispc_clock_info dispc_cinfo
;
54 r
= omap_dss_start_device(dssdev
);
56 DSSERR("failed to start device\n");
60 if (dssdev
->state
!= OMAP_DSS_DISPLAY_DISABLED
) {
61 DSSERR("dssdev already enabled\n");
66 /* In case of skip_init sdi_init has already enabled the clocks */
68 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
73 dssdev
->panel
.config
|= OMAP_DSS_LCD_RF
| OMAP_DSS_LCD_ONOFF
;
75 dispc_set_pol_freq(dssdev
->panel
.config
, dssdev
->panel
.acbi
,
79 r
= dss_calc_clock_div(1, t
->pixel_clock
* 1000,
80 &dss_cinfo
, &dispc_cinfo
);
82 r
= dss_get_clock_div(&dss_cinfo
);
83 r
= dispc_get_clock_div(&dispc_cinfo
);
90 lck_div
= dispc_cinfo
.lck_div
;
91 pck_div
= dispc_cinfo
.pck_div
;
93 pck
= fck
/ lck_div
/ pck_div
/ 1000;
95 if (pck
!= t
->pixel_clock
) {
96 DSSWARN("Could not find exact pixel clock. Requested %d kHz, "
100 t
->pixel_clock
= pck
;
104 dispc_set_lcd_timings(t
);
106 r
= dss_set_clock_div(&dss_cinfo
);
110 r
= dispc_set_clock_div(&dispc_cinfo
);
114 if (!sdi
.skip_init
) {
115 dss_sdi_init(dssdev
->phy
.sdi
.datapairs
);
116 r
= dss_sdi_enable();
122 dispc_enable_lcd_out(1);
124 if (dssdev
->driver
->enable
) {
125 r
= dssdev
->driver
->enable(dssdev
);
130 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
136 dispc_enable_lcd_out(0);
138 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
140 omap_dss_stop_device(dssdev
);
145 static int sdi_display_resume(struct omap_dss_device
*dssdev
);
147 static void sdi_display_disable(struct omap_dss_device
*dssdev
)
149 if (dssdev
->state
== OMAP_DSS_DISPLAY_DISABLED
)
152 if (dssdev
->state
== OMAP_DSS_DISPLAY_SUSPENDED
)
153 if (sdi_display_resume(dssdev
))
156 if (dssdev
->driver
->disable
)
157 dssdev
->driver
->disable(dssdev
);
159 dispc_enable_lcd_out(0);
163 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
165 dssdev
->state
= OMAP_DSS_DISPLAY_DISABLED
;
167 omap_dss_stop_device(dssdev
);
170 static int sdi_display_suspend(struct omap_dss_device
*dssdev
)
172 if (dssdev
->state
!= OMAP_DSS_DISPLAY_ACTIVE
)
175 if (dssdev
->driver
->suspend
)
176 dssdev
->driver
->suspend(dssdev
);
178 dispc_enable_lcd_out(0);
182 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
184 dssdev
->state
= OMAP_DSS_DISPLAY_SUSPENDED
;
189 static int sdi_display_resume(struct omap_dss_device
*dssdev
)
193 if (dssdev
->state
!= OMAP_DSS_DISPLAY_SUSPENDED
)
196 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
198 r
= dss_sdi_enable();
203 dispc_enable_lcd_out(1);
205 if (dssdev
->driver
->resume
)
206 dssdev
->driver
->resume(dssdev
);
208 dssdev
->state
= OMAP_DSS_DISPLAY_ACTIVE
;
212 dss_clk_disable(DSS_CLK_ICK
| DSS_CLK_FCK1
);
216 static int sdi_display_set_update_mode(struct omap_dss_device
*dssdev
,
217 enum omap_dss_update_mode mode
)
219 if (mode
== OMAP_DSS_UPDATE_MANUAL
)
222 if (mode
== OMAP_DSS_UPDATE_DISABLED
) {
223 dispc_enable_lcd_out(0);
224 sdi
.update_enabled
= 0;
226 dispc_enable_lcd_out(1);
227 sdi
.update_enabled
= 1;
233 static enum omap_dss_update_mode
sdi_display_get_update_mode(
234 struct omap_dss_device
*dssdev
)
236 return sdi
.update_enabled
? OMAP_DSS_UPDATE_AUTO
:
237 OMAP_DSS_UPDATE_DISABLED
;
240 static void sdi_get_timings(struct omap_dss_device
*dssdev
,
241 struct omap_video_timings
*timings
)
243 *timings
= dssdev
->panel
.timings
;
246 int sdi_init_display(struct omap_dss_device
*dssdev
)
248 DSSDBG("SDI init\n");
250 dssdev
->enable
= sdi_display_enable
;
251 dssdev
->disable
= sdi_display_disable
;
252 dssdev
->suspend
= sdi_display_suspend
;
253 dssdev
->resume
= sdi_display_resume
;
254 dssdev
->set_update_mode
= sdi_display_set_update_mode
;
255 dssdev
->get_update_mode
= sdi_display_get_update_mode
;
256 dssdev
->get_timings
= sdi_get_timings
;
261 int sdi_init(bool skip_init
)
263 /* we store this for first display enable, then clear it */
264 sdi
.skip_init
= skip_init
;
267 * Enable clocks already here, otherwise there would be a toggle
268 * of them until sdi_display_enable is called.
271 dss_clk_enable(DSS_CLK_ICK
| DSS_CLK_FCK1
);