Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dpi.c
Go to the documentation of this file.
1 /*
2  * linux/drivers/video/omap2/dss/dpi.c
3  *
4  * Copyright (C) 2009 Nokia Corporation
5  * Author: Tomi Valkeinen <[email protected]>
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>
32 #include <linux/string.h>
33 
34 #include <video/omapdss.h>
35 
36 #include "dss.h"
37 #include "dss_features.h"
38 
39 static struct {
42 
43  struct mutex lock;
44 
48 
50 } dpi;
51 
52 static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
53 {
54  int dsi_module;
55 
56  dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
57 
58  return dsi_get_dsidev_from_id(dsi_module);
59 }
60 
61 static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
62 {
63  if (dssdev->clocks.dispc.dispc_fclk_src ==
65  dssdev->clocks.dispc.dispc_fclk_src ==
67  dssdev->clocks.dispc.channel.lcd_clk_src ==
69  dssdev->clocks.dispc.channel.lcd_clk_src ==
71  return true;
72  else
73  return false;
74 }
75 
76 static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
77  unsigned long pck_req, unsigned long *fck, int *lck_div,
78  int *pck_div)
79 {
80  struct dsi_clock_info dsi_cinfo;
81  struct dispc_clock_info dispc_cinfo;
82  int r;
83 
84  r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
85  &dispc_cinfo);
86  if (r)
87  return r;
88 
89  r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
90  if (r)
91  return r;
92 
93  dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
94 
95  dpi.mgr_config.clock_info = dispc_cinfo;
96 
97  *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
98  *lck_div = dispc_cinfo.lck_div;
99  *pck_div = dispc_cinfo.pck_div;
100 
101  return 0;
102 }
103 
104 static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
105  unsigned long pck_req, unsigned long *fck, int *lck_div,
106  int *pck_div)
107 {
108  struct dss_clock_info dss_cinfo;
109  struct dispc_clock_info dispc_cinfo;
110  int r;
111 
112  r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
113  if (r)
114  return r;
115 
116  r = dss_set_clock_div(&dss_cinfo);
117  if (r)
118  return r;
119 
120  dpi.mgr_config.clock_info = dispc_cinfo;
121 
122  *fck = dss_cinfo.fck;
123  *lck_div = dispc_cinfo.lck_div;
124  *pck_div = dispc_cinfo.pck_div;
125 
126  return 0;
127 }
128 
129 static int dpi_set_mode(struct omap_dss_device *dssdev)
130 {
131  struct omap_video_timings *t = &dpi.timings;
132  struct omap_overlay_manager *mgr = dssdev->output->manager;
133  int lck_div = 0, pck_div = 0;
134  unsigned long fck = 0;
135  unsigned long pck;
136  int r = 0;
137 
138  if (dpi_use_dsi_pll(dssdev))
139  r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
140  &lck_div, &pck_div);
141  else
142  r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck,
143  &lck_div, &pck_div);
144  if (r)
145  return r;
146 
147  pck = fck / lck_div / pck_div / 1000;
148 
149  if (pck != t->pixel_clock) {
150  DSSWARN("Could not find exact pixel clock. "
151  "Requested %d kHz, got %lu kHz\n",
152  t->pixel_clock, pck);
153 
154  t->pixel_clock = pck;
155  }
156 
157  dss_mgr_set_timings(mgr, t);
158 
159  return 0;
160 }
161 
162 static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
163 {
164  struct omap_overlay_manager *mgr = dssdev->output->manager;
165 
166  dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
167 
168  dpi.mgr_config.stallmode = false;
169  dpi.mgr_config.fifohandcheck = false;
170 
171  dpi.mgr_config.video_port_width = dpi.data_lines;
172 
173  dpi.mgr_config.lcden_sig_polarity = 0;
174 
175  dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
176 }
177 
179 {
180  struct omap_dss_output *out = dssdev->output;
181  int r;
182 
183  mutex_lock(&dpi.lock);
184 
185  if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
186  DSSERR("no VDSS_DSI regulator\n");
187  r = -ENODEV;
188  goto err_no_reg;
189  }
190 
191  if (out == NULL || out->manager == NULL) {
192  DSSERR("failed to enable display: no output/manager\n");
193  r = -ENODEV;
194  goto err_no_out_mgr;
195  }
196 
197  r = omap_dss_start_device(dssdev);
198  if (r) {
199  DSSERR("failed to start device\n");
200  goto err_start_dev;
201  }
202 
204  r = regulator_enable(dpi.vdds_dsi_reg);
205  if (r)
206  goto err_reg_enable;
207  }
208 
209  r = dispc_runtime_get();
210  if (r)
211  goto err_get_dispc;
212 
213  r = dss_dpi_select_source(dssdev->channel);
214  if (r)
215  goto err_src_sel;
216 
217  if (dpi_use_dsi_pll(dssdev)) {
218  r = dsi_runtime_get(dpi.dsidev);
219  if (r)
220  goto err_get_dsi;
221 
222  r = dsi_pll_init(dpi.dsidev, 0, 1);
223  if (r)
224  goto err_dsi_pll_init;
225  }
226 
227  r = dpi_set_mode(dssdev);
228  if (r)
229  goto err_set_mode;
230 
231  dpi_config_lcd_manager(dssdev);
232 
233  mdelay(2);
234 
235  r = dss_mgr_enable(out->manager);
236  if (r)
237  goto err_mgr_enable;
238 
239  mutex_unlock(&dpi.lock);
240 
241  return 0;
242 
243 err_mgr_enable:
244 err_set_mode:
245  if (dpi_use_dsi_pll(dssdev))
246  dsi_pll_uninit(dpi.dsidev, true);
247 err_dsi_pll_init:
248  if (dpi_use_dsi_pll(dssdev))
249  dsi_runtime_put(dpi.dsidev);
250 err_get_dsi:
251 err_src_sel:
253 err_get_dispc:
255  regulator_disable(dpi.vdds_dsi_reg);
256 err_reg_enable:
257  omap_dss_stop_device(dssdev);
258 err_start_dev:
259 err_no_out_mgr:
260 err_no_reg:
261  mutex_unlock(&dpi.lock);
262  return r;
263 }
265 
267 {
268  struct omap_overlay_manager *mgr = dssdev->output->manager;
269 
270  mutex_lock(&dpi.lock);
271 
272  dss_mgr_disable(mgr);
273 
274  if (dpi_use_dsi_pll(dssdev)) {
276  dsi_pll_uninit(dpi.dsidev, true);
277  dsi_runtime_put(dpi.dsidev);
278  }
279 
281 
283  regulator_disable(dpi.vdds_dsi_reg);
284 
285  omap_dss_stop_device(dssdev);
286 
287  mutex_unlock(&dpi.lock);
288 }
290 
292  struct omap_video_timings *timings)
293 {
294  DSSDBG("dpi_set_timings\n");
295 
296  mutex_lock(&dpi.lock);
297 
298  dpi.timings = *timings;
299 
300  mutex_unlock(&dpi.lock);
301 }
303 
305  struct omap_video_timings *timings)
306 {
307  int r;
308  struct omap_overlay_manager *mgr = dssdev->output->manager;
309  int lck_div, pck_div;
310  unsigned long fck;
311  unsigned long pck;
312  struct dispc_clock_info dispc_cinfo;
313 
314  if (dss_mgr_check_timings(mgr, timings))
315  return -EINVAL;
316 
317  if (timings->pixel_clock == 0)
318  return -EINVAL;
319 
320  if (dpi_use_dsi_pll(dssdev)) {
321  struct dsi_clock_info dsi_cinfo;
322  r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
323  timings->pixel_clock * 1000,
324  &dsi_cinfo, &dispc_cinfo);
325 
326  if (r)
327  return r;
328 
329  fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
330  } else {
331  struct dss_clock_info dss_cinfo;
332  r = dss_calc_clock_div(timings->pixel_clock * 1000,
333  &dss_cinfo, &dispc_cinfo);
334 
335  if (r)
336  return r;
337 
338  fck = dss_cinfo.fck;
339  }
340 
341  lck_div = dispc_cinfo.lck_div;
342  pck_div = dispc_cinfo.pck_div;
343 
344  pck = fck / lck_div / pck_div / 1000;
345 
346  timings->pixel_clock = pck;
347 
348  return 0;
349 }
351 
353 {
354  mutex_lock(&dpi.lock);
355 
356  dpi.data_lines = data_lines;
357 
358  mutex_unlock(&dpi.lock);
359 }
361 
362 static int __init dpi_init_display(struct omap_dss_device *dssdev)
363 {
364  DSSDBG("init_display\n");
365 
367  dpi.vdds_dsi_reg == NULL) {
368  struct regulator *vdds_dsi;
369 
370  vdds_dsi = dss_get_vdds_dsi();
371 
372  if (IS_ERR(vdds_dsi)) {
373  DSSERR("can't get VDDS_DSI regulator\n");
374  return PTR_ERR(vdds_dsi);
375  }
376 
377  dpi.vdds_dsi_reg = vdds_dsi;
378  }
379 
380  if (dpi_use_dsi_pll(dssdev)) {
381  enum omap_dss_clk_source dispc_fclk_src =
382  dssdev->clocks.dispc.dispc_fclk_src;
383  dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
384  }
385 
386  return 0;
387 }
388 
389 static struct omap_dss_device * __init dpi_find_dssdev(struct platform_device *pdev)
390 {
391  struct omap_dss_board_info *pdata = pdev->dev.platform_data;
392  const char *def_disp_name = dss_get_default_display_name();
393  struct omap_dss_device *def_dssdev;
394  int i;
395 
396  def_dssdev = NULL;
397 
398  for (i = 0; i < pdata->num_devices; ++i) {
399  struct omap_dss_device *dssdev = pdata->devices[i];
400 
401  if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
402  continue;
403 
404  if (def_dssdev == NULL)
405  def_dssdev = dssdev;
406 
407  if (def_disp_name != NULL &&
408  strcmp(dssdev->name, def_disp_name) == 0) {
409  def_dssdev = dssdev;
410  break;
411  }
412  }
413 
414  return def_dssdev;
415 }
416 
417 static void __init dpi_probe_pdata(struct platform_device *dpidev)
418 {
419  struct omap_dss_device *plat_dssdev;
420  struct omap_dss_device *dssdev;
421  int r;
422 
423  plat_dssdev = dpi_find_dssdev(dpidev);
424 
425  if (!plat_dssdev)
426  return;
427 
428  dssdev = dss_alloc_and_init_device(&dpidev->dev);
429  if (!dssdev)
430  return;
431 
432  dss_copy_device_pdata(dssdev, plat_dssdev);
433 
434  r = dpi_init_display(dssdev);
435  if (r) {
436  DSSERR("device %s init failed: %d\n", dssdev->name, r);
437  dss_put_device(dssdev);
438  return;
439  }
440 
441  r = dss_add_device(dssdev);
442  if (r) {
443  DSSERR("device %s register failed: %d\n", dssdev->name, r);
444  dss_put_device(dssdev);
445  return;
446  }
447 }
448 
449 static void __init dpi_init_output(struct platform_device *pdev)
450 {
451  struct omap_dss_output *out = &dpi.output;
452 
453  out->pdev = pdev;
454  out->id = OMAP_DSS_OUTPUT_DPI;
456 
457  dss_register_output(out);
458 }
459 
460 static void __exit dpi_uninit_output(struct platform_device *pdev)
461 {
462  struct omap_dss_output *out = &dpi.output;
463 
465 }
466 
467 static int __init omap_dpi_probe(struct platform_device *pdev)
468 {
469  mutex_init(&dpi.lock);
470 
471  dpi_init_output(pdev);
472 
473  dpi_probe_pdata(pdev);
474 
475  return 0;
476 }
477 
478 static int __exit omap_dpi_remove(struct platform_device *pdev)
479 {
481 
482  dpi_uninit_output(pdev);
483 
484  return 0;
485 }
486 
487 static struct platform_driver omap_dpi_driver = {
488  .remove = __exit_p(omap_dpi_remove),
489  .driver = {
490  .name = "omapdss_dpi",
491  .owner = THIS_MODULE,
492  },
493 };
494 
496 {
497  return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe);
498 }
499 
501 {
502  platform_driver_unregister(&omap_dpi_driver);
503 }