]> Pileus Git - ~andy/linux/blob - drivers/video/omap2/dss/dpi.c
Merge tag 'fbdev-updates-for-3.6' of git://github.com/schandinat/linux-2.6
[~andy/linux] / drivers / video / omap2 / dss / dpi.c
1 /*
2  * linux/drivers/video/omap2/dss/dpi.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
6  *
7  * Some code and ideas taken from drivers/video/omap/ driver
8  * by Imre Deak.
9  *
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License version 2 as published by
12  * the Free Software Foundation.
13  *
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
17  * more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * this program.  If not, see <http://www.gnu.org/licenses/>.
21  */
22
23 #define DSS_SUBSYS_NAME "DPI"
24
25 #include <linux/kernel.h>
26 #include <linux/delay.h>
27 #include <linux/export.h>
28 #include <linux/err.h>
29 #include <linux/errno.h>
30 #include <linux/platform_device.h>
31 #include <linux/regulator/consumer.h>
32
33 #include <video/omapdss.h>
34 #include <plat/cpu.h>
35
36 #include "dss.h"
37
38 static struct {
39         struct regulator *vdds_dsi_reg;
40         struct platform_device *dsidev;
41
42         struct dss_lcd_mgr_config mgr_config;
43 } dpi;
44
45 static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
46 {
47         int dsi_module;
48
49         dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
50
51         return dsi_get_dsidev_from_id(dsi_module);
52 }
53
54 static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
55 {
56         if (dssdev->clocks.dispc.dispc_fclk_src ==
57                         OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
58                         dssdev->clocks.dispc.dispc_fclk_src ==
59                         OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
60                         dssdev->clocks.dispc.channel.lcd_clk_src ==
61                         OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
62                         dssdev->clocks.dispc.channel.lcd_clk_src ==
63                         OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
64                 return true;
65         else
66                 return false;
67 }
68
69 static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
70                 unsigned long pck_req, unsigned long *fck, int *lck_div,
71                 int *pck_div)
72 {
73         struct dsi_clock_info dsi_cinfo;
74         struct dispc_clock_info dispc_cinfo;
75         int r;
76
77         r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
78                         &dispc_cinfo);
79         if (r)
80                 return r;
81
82         r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
83         if (r)
84                 return r;
85
86         dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
87
88         dpi.mgr_config.clock_info = dispc_cinfo;
89
90         *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
91         *lck_div = dispc_cinfo.lck_div;
92         *pck_div = dispc_cinfo.pck_div;
93
94         return 0;
95 }
96
97 static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
98                 unsigned long pck_req, unsigned long *fck, int *lck_div,
99                 int *pck_div)
100 {
101         struct dss_clock_info dss_cinfo;
102         struct dispc_clock_info dispc_cinfo;
103         int r;
104
105         r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
106         if (r)
107                 return r;
108
109         r = dss_set_clock_div(&dss_cinfo);
110         if (r)
111                 return r;
112
113         dpi.mgr_config.clock_info = dispc_cinfo;
114
115         *fck = dss_cinfo.fck;
116         *lck_div = dispc_cinfo.lck_div;
117         *pck_div = dispc_cinfo.pck_div;
118
119         return 0;
120 }
121
122 static int dpi_set_mode(struct omap_dss_device *dssdev)
123 {
124         struct omap_video_timings *t = &dssdev->panel.timings;
125         int lck_div = 0, pck_div = 0;
126         unsigned long fck = 0;
127         unsigned long pck;
128         int r = 0;
129
130         if (dpi_use_dsi_pll(dssdev))
131                 r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
132                                 &lck_div, &pck_div);
133         else
134                 r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck,
135                                 &lck_div, &pck_div);
136         if (r)
137                 return r;
138
139         pck = fck / lck_div / pck_div / 1000;
140
141         if (pck != t->pixel_clock) {
142                 DSSWARN("Could not find exact pixel clock. "
143                                 "Requested %d kHz, got %lu kHz\n",
144                                 t->pixel_clock, pck);
145
146                 t->pixel_clock = pck;
147         }
148
149         dss_mgr_set_timings(dssdev->manager, t);
150
151         return 0;
152 }
153
154 static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
155 {
156         dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
157
158         dpi.mgr_config.stallmode = false;
159         dpi.mgr_config.fifohandcheck = false;
160
161         dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines;
162
163         dpi.mgr_config.lcden_sig_polarity = 0;
164
165         dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config);
166 }
167
168 int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
169 {
170         int r;
171
172         if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
173                 DSSERR("no VDSS_DSI regulator\n");
174                 return -ENODEV;
175         }
176
177         if (dssdev->manager == NULL) {
178                 DSSERR("failed to enable display: no manager\n");
179                 return -ENODEV;
180         }
181
182         r = omap_dss_start_device(dssdev);
183         if (r) {
184                 DSSERR("failed to start device\n");
185                 goto err_start_dev;
186         }
187
188         if (cpu_is_omap34xx()) {
189                 r = regulator_enable(dpi.vdds_dsi_reg);
190                 if (r)
191                         goto err_reg_enable;
192         }
193
194         r = dispc_runtime_get();
195         if (r)
196                 goto err_get_dispc;
197
198         if (dpi_use_dsi_pll(dssdev)) {
199                 r = dsi_runtime_get(dpi.dsidev);
200                 if (r)
201                         goto err_get_dsi;
202
203                 r = dsi_pll_init(dpi.dsidev, 0, 1);
204                 if (r)
205                         goto err_dsi_pll_init;
206         }
207
208         r = dpi_set_mode(dssdev);
209         if (r)
210                 goto err_set_mode;
211
212         dpi_config_lcd_manager(dssdev);
213
214         mdelay(2);
215
216         r = dss_mgr_enable(dssdev->manager);
217         if (r)
218                 goto err_mgr_enable;
219
220         return 0;
221
222 err_mgr_enable:
223 err_set_mode:
224         if (dpi_use_dsi_pll(dssdev))
225                 dsi_pll_uninit(dpi.dsidev, true);
226 err_dsi_pll_init:
227         if (dpi_use_dsi_pll(dssdev))
228                 dsi_runtime_put(dpi.dsidev);
229 err_get_dsi:
230         dispc_runtime_put();
231 err_get_dispc:
232         if (cpu_is_omap34xx())
233                 regulator_disable(dpi.vdds_dsi_reg);
234 err_reg_enable:
235         omap_dss_stop_device(dssdev);
236 err_start_dev:
237         return r;
238 }
239 EXPORT_SYMBOL(omapdss_dpi_display_enable);
240
241 void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
242 {
243         dss_mgr_disable(dssdev->manager);
244
245         if (dpi_use_dsi_pll(dssdev)) {
246                 dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
247                 dsi_pll_uninit(dpi.dsidev, true);
248                 dsi_runtime_put(dpi.dsidev);
249         }
250
251         dispc_runtime_put();
252
253         if (cpu_is_omap34xx())
254                 regulator_disable(dpi.vdds_dsi_reg);
255
256         omap_dss_stop_device(dssdev);
257 }
258 EXPORT_SYMBOL(omapdss_dpi_display_disable);
259
260 void dpi_set_timings(struct omap_dss_device *dssdev,
261                         struct omap_video_timings *timings)
262 {
263         int r;
264
265         DSSDBG("dpi_set_timings\n");
266         dssdev->panel.timings = *timings;
267         if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
268                 r = dispc_runtime_get();
269                 if (r)
270                         return;
271
272                 dpi_set_mode(dssdev);
273
274                 dispc_runtime_put();
275         } else {
276                 dss_mgr_set_timings(dssdev->manager, timings);
277         }
278 }
279 EXPORT_SYMBOL(dpi_set_timings);
280
281 int dpi_check_timings(struct omap_dss_device *dssdev,
282                         struct omap_video_timings *timings)
283 {
284         int r;
285         int lck_div, pck_div;
286         unsigned long fck;
287         unsigned long pck;
288         struct dispc_clock_info dispc_cinfo;
289
290         if (dss_mgr_check_timings(dssdev->manager, timings))
291                 return -EINVAL;
292
293         if (timings->pixel_clock == 0)
294                 return -EINVAL;
295
296         if (dpi_use_dsi_pll(dssdev)) {
297                 struct dsi_clock_info dsi_cinfo;
298                 r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
299                                 timings->pixel_clock * 1000,
300                                 &dsi_cinfo, &dispc_cinfo);
301
302                 if (r)
303                         return r;
304
305                 fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
306         } else {
307                 struct dss_clock_info dss_cinfo;
308                 r = dss_calc_clock_div(timings->pixel_clock * 1000,
309                                 &dss_cinfo, &dispc_cinfo);
310
311                 if (r)
312                         return r;
313
314                 fck = dss_cinfo.fck;
315         }
316
317         lck_div = dispc_cinfo.lck_div;
318         pck_div = dispc_cinfo.pck_div;
319
320         pck = fck / lck_div / pck_div / 1000;
321
322         timings->pixel_clock = pck;
323
324         return 0;
325 }
326 EXPORT_SYMBOL(dpi_check_timings);
327
328 static int __init dpi_init_display(struct omap_dss_device *dssdev)
329 {
330         DSSDBG("init_display\n");
331
332         if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
333                 struct regulator *vdds_dsi;
334
335                 vdds_dsi = dss_get_vdds_dsi();
336
337                 if (IS_ERR(vdds_dsi)) {
338                         DSSERR("can't get VDDS_DSI regulator\n");
339                         return PTR_ERR(vdds_dsi);
340                 }
341
342                 dpi.vdds_dsi_reg = vdds_dsi;
343         }
344
345         if (dpi_use_dsi_pll(dssdev)) {
346                 enum omap_dss_clk_source dispc_fclk_src =
347                         dssdev->clocks.dispc.dispc_fclk_src;
348                 dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
349         }
350
351         return 0;
352 }
353
354 static void __init dpi_probe_pdata(struct platform_device *pdev)
355 {
356         struct omap_dss_board_info *pdata = pdev->dev.platform_data;
357         int i, r;
358
359         for (i = 0; i < pdata->num_devices; ++i) {
360                 struct omap_dss_device *dssdev = pdata->devices[i];
361
362                 if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
363                         continue;
364
365                 r = dpi_init_display(dssdev);
366                 if (r) {
367                         DSSERR("device %s init failed: %d\n", dssdev->name, r);
368                         continue;
369                 }
370
371                 r = omap_dss_register_device(dssdev, &pdev->dev, i);
372                 if (r)
373                         DSSERR("device %s register failed: %d\n",
374                                         dssdev->name, r);
375         }
376 }
377
378 static int __init omap_dpi_probe(struct platform_device *pdev)
379 {
380         dpi_probe_pdata(pdev);
381
382         return 0;
383 }
384
385 static int __exit omap_dpi_remove(struct platform_device *pdev)
386 {
387         omap_dss_unregister_child_devices(&pdev->dev);
388
389         return 0;
390 }
391
392 static struct platform_driver omap_dpi_driver = {
393         .remove         = __exit_p(omap_dpi_remove),
394         .driver         = {
395                 .name   = "omapdss_dpi",
396                 .owner  = THIS_MODULE,
397         },
398 };
399
400 int __init dpi_init_platform_driver(void)
401 {
402         return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe);
403 }
404
405 void __exit dpi_uninit_platform_driver(void)
406 {
407         platform_driver_unregister(&omap_dpi_driver);
408 }