video: replace strict_strtoul() with kstrtoul()
[deliverable/linux.git] / drivers / video / omap2 / dss / dpi.c
CommitLineData
553c48cf
TV
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>
553c48cf 26#include <linux/delay.h>
a8a35931 27#include <linux/export.h>
8a2cfea8 28#include <linux/err.h>
553c48cf 29#include <linux/errno.h>
8a2cfea8
TV
30#include <linux/platform_device.h>
31#include <linux/regulator/consumer.h>
13b1ba7d 32#include <linux/string.h>
553c48cf 33
a0b38cc4 34#include <video/omapdss.h>
553c48cf
TV
35
36#include "dss.h"
195e672a 37#include "dss_features.h"
553c48cf
TV
38
39static struct {
8a2cfea8 40 struct regulator *vdds_dsi_reg;
a72b64b9 41 struct platform_device *dsidev;
5cf9a264 42
c8a5e4e8
AT
43 struct mutex lock;
44
c499144c 45 struct omap_video_timings timings;
5cf9a264 46 struct dss_lcd_mgr_config mgr_config;
c6b393d4 47 int data_lines;
81b87f51
AT
48
49 struct omap_dss_output output;
553c48cf
TV
50} dpi;
51
0e8276ef 52static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
a72b64b9 53{
bd0f5cc3
TV
54 /*
55 * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
56 * would also be used for DISPC fclk. Meaning, when the DPI output is
57 * disabled, DISPC clock will be disabled, and TV out will stop.
58 */
59 switch (omapdss_get_version()) {
60 case OMAPDSS_VER_OMAP24xx:
61 case OMAPDSS_VER_OMAP34xx_ES1:
62 case OMAPDSS_VER_OMAP34xx_ES3:
63 case OMAPDSS_VER_OMAP3630:
64 case OMAPDSS_VER_AM35xx:
65 return NULL;
bd0f5cc3 66
f8ad984c
TV
67 case OMAPDSS_VER_OMAP4430_ES1:
68 case OMAPDSS_VER_OMAP4430_ES2:
69 case OMAPDSS_VER_OMAP4:
70 switch (channel) {
71 case OMAP_DSS_CHANNEL_LCD:
72 return dsi_get_dsidev_from_id(0);
73 case OMAP_DSS_CHANNEL_LCD2:
74 return dsi_get_dsidev_from_id(1);
75 default:
76 return NULL;
77 }
78
79 case OMAPDSS_VER_OMAP5:
80 switch (channel) {
81 case OMAP_DSS_CHANNEL_LCD:
82 return dsi_get_dsidev_from_id(0);
83 case OMAP_DSS_CHANNEL_LCD3:
84 return dsi_get_dsidev_from_id(1);
85 default:
86 return NULL;
87 }
88
0e8276ef
TV
89 default:
90 return NULL;
91 }
a72b64b9
AT
92}
93
0e8276ef 94static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
7636b3b4 95{
0e8276ef
TV
96 switch (channel) {
97 case OMAP_DSS_CHANNEL_LCD:
98 return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
99 case OMAP_DSS_CHANNEL_LCD2:
100 return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
101 default:
102 /* this shouldn't happen */
103 WARN_ON(1);
104 return OMAP_DSS_CLK_SRC_FCK;
105 }
7636b3b4
AT
106}
107
100c8262
TV
108struct dpi_clk_calc_ctx {
109 struct platform_device *dsidev;
110
111 /* inputs */
112
113 unsigned long pck_min, pck_max;
114
115 /* outputs */
116
117 struct dsi_clock_info dsi_cinfo;
118 struct dss_clock_info dss_cinfo;
119 struct dispc_clock_info dispc_cinfo;
120};
121
122static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
123 unsigned long pck, void *data)
124{
125 struct dpi_clk_calc_ctx *ctx = data;
126
127 /*
128 * Odd dividers give us uneven duty cycle, causing problem when level
129 * shifted. So skip all odd dividers when the pixel clock is on the
130 * higher side.
131 */
132 if (ctx->pck_min >= 1000000) {
133 if (lckd > 1 && lckd % 2 != 0)
134 return false;
135
136 if (pckd > 1 && pckd % 2 != 0)
137 return false;
138 }
139
140 ctx->dispc_cinfo.lck_div = lckd;
141 ctx->dispc_cinfo.pck_div = pckd;
142 ctx->dispc_cinfo.lck = lck;
143 ctx->dispc_cinfo.pck = pck;
144
145 return true;
146}
147
148
149static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
150 void *data)
151{
152 struct dpi_clk_calc_ctx *ctx = data;
153
154 /*
155 * Odd dividers give us uneven duty cycle, causing problem when level
156 * shifted. So skip all odd dividers when the pixel clock is on the
157 * higher side.
158 */
159 if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 1000000)
160 return false;
161
162 ctx->dsi_cinfo.regm_dispc = regm_dispc;
163 ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
164
165 return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
166 dpi_calc_dispc_cb, ctx);
167}
168
169
170static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
171 unsigned long pll,
172 void *data)
173{
174 struct dpi_clk_calc_ctx *ctx = data;
175
176 ctx->dsi_cinfo.regn = regn;
177 ctx->dsi_cinfo.regm = regm;
178 ctx->dsi_cinfo.fint = fint;
179 ctx->dsi_cinfo.clkin4ddr = pll;
180
181 return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
182 dpi_calc_hsdiv_cb, ctx);
183}
184
185static bool dpi_calc_dss_cb(int fckd, unsigned long fck, void *data)
186{
187 struct dpi_clk_calc_ctx *ctx = data;
188
189 ctx->dss_cinfo.fck = fck;
190 ctx->dss_cinfo.fck_div = fckd;
191
192 return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
193 dpi_calc_dispc_cb, ctx);
194}
195
196static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
197{
198 unsigned long clkin;
199 unsigned long pll_min, pll_max;
200
201 clkin = dsi_get_pll_clkin(dpi.dsidev);
202
203 memset(ctx, 0, sizeof(*ctx));
204 ctx->dsidev = dpi.dsidev;
205 ctx->pck_min = pck - 1000;
206 ctx->pck_max = pck + 1000;
207 ctx->dsi_cinfo.clkin = clkin;
208
209 pll_min = 0;
210 pll_max = 0;
211
212 return dsi_pll_calc(dpi.dsidev, clkin,
213 pll_min, pll_max,
214 dpi_calc_pll_cb, ctx);
215}
216
217static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
218{
219 int i;
220
221 /*
222 * DSS fck gives us very few possibilities, so finding a good pixel
223 * clock may not be possible. We try multiple times to find the clock,
224 * each time widening the pixel clock range we look for, up to
2c6360fb 225 * +/- ~15MHz.
100c8262
TV
226 */
227
2c6360fb 228 for (i = 0; i < 25; ++i) {
100c8262
TV
229 bool ok;
230
231 memset(ctx, 0, sizeof(*ctx));
232 if (pck > 1000 * i * i * i)
233 ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
234 else
235 ctx->pck_min = 0;
236 ctx->pck_max = pck + 1000 * i * i * i;
237
238 ok = dss_div_calc(ctx->pck_min, dpi_calc_dss_cb, ctx);
239 if (ok)
240 return ok;
241 }
242
243 return false;
244}
245
246
247
03a0d1e8 248static int dpi_set_dsi_clk(enum omap_channel channel,
ff1b2cde
SS
249 unsigned long pck_req, unsigned long *fck, int *lck_div,
250 int *pck_div)
553c48cf 251{
100c8262 252 struct dpi_clk_calc_ctx ctx;
553c48cf 253 int r;
100c8262 254 bool ok;
553c48cf 255
100c8262
TV
256 ok = dpi_dsi_clk_calc(pck_req, &ctx);
257 if (!ok)
258 return -EINVAL;
553c48cf 259
100c8262 260 r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
553c48cf
TV
261 if (r)
262 return r;
263
03a0d1e8
TV
264 dss_select_lcd_clk_source(channel,
265 dpi_get_alt_clk_src(channel));
553c48cf 266
100c8262 267 dpi.mgr_config.clock_info = ctx.dispc_cinfo;
553c48cf 268
100c8262
TV
269 *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
270 *lck_div = ctx.dispc_cinfo.lck_div;
271 *pck_div = ctx.dispc_cinfo.pck_div;
553c48cf
TV
272
273 return 0;
274}
7636b3b4 275
03a0d1e8
TV
276static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
277 int *lck_div, int *pck_div)
553c48cf 278{
100c8262 279 struct dpi_clk_calc_ctx ctx;
553c48cf 280 int r;
100c8262 281 bool ok;
553c48cf 282
100c8262
TV
283 ok = dpi_dss_clk_calc(pck_req, &ctx);
284 if (!ok)
285 return -EINVAL;
553c48cf 286
100c8262 287 r = dss_set_clock_div(&ctx.dss_cinfo);
553c48cf
TV
288 if (r)
289 return r;
290
100c8262 291 dpi.mgr_config.clock_info = ctx.dispc_cinfo;
553c48cf 292
100c8262
TV
293 *fck = ctx.dss_cinfo.fck;
294 *lck_div = ctx.dispc_cinfo.lck_div;
295 *pck_div = ctx.dispc_cinfo.pck_div;
553c48cf
TV
296
297 return 0;
298}
553c48cf 299
03a0d1e8 300static int dpi_set_mode(struct omap_overlay_manager *mgr)
553c48cf 301{
c499144c 302 struct omap_video_timings *t = &dpi.timings;
7636b3b4
AT
303 int lck_div = 0, pck_div = 0;
304 unsigned long fck = 0;
553c48cf 305 unsigned long pck;
553c48cf
TV
306 int r = 0;
307
8a3db406 308 if (dpi.dsidev)
03a0d1e8 309 r = dpi_set_dsi_clk(mgr->id, t->pixel_clock * 1000, &fck,
6d523e7b 310 &lck_div, &pck_div);
7636b3b4 311 else
03a0d1e8 312 r = dpi_set_dispc_clk(t->pixel_clock * 1000, &fck,
6d523e7b 313 &lck_div, &pck_div);
553c48cf 314 if (r)
4fbafaf3 315 return r;
553c48cf
TV
316
317 pck = fck / lck_div / pck_div / 1000;
318
319 if (pck != t->pixel_clock) {
320 DSSWARN("Could not find exact pixel clock. "
321 "Requested %d kHz, got %lu kHz\n",
322 t->pixel_clock, pck);
323
324 t->pixel_clock = pck;
325 }
326
5d512fcd 327 dss_mgr_set_timings(mgr, t);
553c48cf 328
4fbafaf3 329 return 0;
553c48cf
TV
330}
331
03a0d1e8 332static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
553c48cf 333{
5cf9a264 334 dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
569969d6 335
5cf9a264
AT
336 dpi.mgr_config.stallmode = false;
337 dpi.mgr_config.fifohandcheck = false;
338
c6b393d4 339 dpi.mgr_config.video_port_width = dpi.data_lines;
5cf9a264
AT
340
341 dpi.mgr_config.lcden_sig_polarity = 0;
342
5d512fcd 343 dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
553c48cf
TV
344}
345
37ac60e4 346int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
553c48cf 347{
03a0d1e8 348 struct omap_dss_output *out = &dpi.output;
553c48cf
TV
349 int r;
350
c8a5e4e8
AT
351 mutex_lock(&dpi.lock);
352
195e672a 353 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
40410715 354 DSSERR("no VDSS_DSI regulator\n");
c8a5e4e8
AT
355 r = -ENODEV;
356 goto err_no_reg;
40410715
RK
357 }
358
5d512fcd
AT
359 if (out == NULL || out->manager == NULL) {
360 DSSERR("failed to enable display: no output/manager\n");
c8a5e4e8 361 r = -ENODEV;
5d512fcd 362 goto err_no_out_mgr;
05e1d606
TV
363 }
364
553c48cf
TV
365 r = omap_dss_start_device(dssdev);
366 if (r) {
367 DSSERR("failed to start device\n");
4fbafaf3 368 goto err_start_dev;
553c48cf
TV
369 }
370
195e672a 371 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
8a2cfea8
TV
372 r = regulator_enable(dpi.vdds_dsi_reg);
373 if (r)
4fbafaf3 374 goto err_reg_enable;
8a2cfea8
TV
375 }
376
4fbafaf3 377 r = dispc_runtime_get();
553c48cf 378 if (r)
4fbafaf3
TV
379 goto err_get_dispc;
380
03a0d1e8 381 r = dss_dpi_select_source(out->manager->id);
de09e455
TV
382 if (r)
383 goto err_src_sel;
384
8a3db406 385 if (dpi.dsidev) {
4fbafaf3
TV
386 r = dsi_runtime_get(dpi.dsidev);
387 if (r)
388 goto err_get_dsi;
389
a72b64b9 390 r = dsi_pll_init(dpi.dsidev, 0, 1);
7636b3b4 391 if (r)
4fbafaf3 392 goto err_dsi_pll_init;
7636b3b4
AT
393 }
394
03a0d1e8 395 r = dpi_set_mode(out->manager);
553c48cf 396 if (r)
4fbafaf3 397 goto err_set_mode;
553c48cf 398
03a0d1e8 399 dpi_config_lcd_manager(out->manager);
5cf9a264 400
553c48cf
TV
401 mdelay(2);
402
5d512fcd 403 r = dss_mgr_enable(out->manager);
33ca237f
TV
404 if (r)
405 goto err_mgr_enable;
553c48cf 406
c8a5e4e8
AT
407 mutex_unlock(&dpi.lock);
408
553c48cf
TV
409 return 0;
410
33ca237f 411err_mgr_enable:
4fbafaf3 412err_set_mode:
8a3db406 413 if (dpi.dsidev)
19077a73 414 dsi_pll_uninit(dpi.dsidev, true);
4fbafaf3 415err_dsi_pll_init:
8a3db406 416 if (dpi.dsidev)
4fbafaf3
TV
417 dsi_runtime_put(dpi.dsidev);
418err_get_dsi:
de09e455 419err_src_sel:
4fbafaf3
TV
420 dispc_runtime_put();
421err_get_dispc:
195e672a 422 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
8a2cfea8 423 regulator_disable(dpi.vdds_dsi_reg);
4fbafaf3 424err_reg_enable:
553c48cf 425 omap_dss_stop_device(dssdev);
4fbafaf3 426err_start_dev:
5d512fcd 427err_no_out_mgr:
c8a5e4e8
AT
428err_no_reg:
429 mutex_unlock(&dpi.lock);
553c48cf
TV
430 return r;
431}
37ac60e4 432EXPORT_SYMBOL(omapdss_dpi_display_enable);
553c48cf 433
37ac60e4 434void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
553c48cf 435{
03a0d1e8 436 struct omap_overlay_manager *mgr = dpi.output.manager;
5d512fcd 437
c8a5e4e8
AT
438 mutex_lock(&dpi.lock);
439
5d512fcd 440 dss_mgr_disable(mgr);
553c48cf 441
8a3db406 442 if (dpi.dsidev) {
a5b8399f 443 dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
a72b64b9 444 dsi_pll_uninit(dpi.dsidev, true);
4fbafaf3 445 dsi_runtime_put(dpi.dsidev);
7636b3b4 446 }
553c48cf 447
4fbafaf3 448 dispc_runtime_put();
553c48cf 449
195e672a 450 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
8a2cfea8
TV
451 regulator_disable(dpi.vdds_dsi_reg);
452
553c48cf 453 omap_dss_stop_device(dssdev);
c8a5e4e8
AT
454
455 mutex_unlock(&dpi.lock);
553c48cf 456}
37ac60e4 457EXPORT_SYMBOL(omapdss_dpi_display_disable);
553c48cf 458
c499144c
AT
459void omapdss_dpi_set_timings(struct omap_dss_device *dssdev,
460 struct omap_video_timings *timings)
553c48cf
TV
461{
462 DSSDBG("dpi_set_timings\n");
c8a5e4e8
AT
463
464 mutex_lock(&dpi.lock);
465
c499144c 466 dpi.timings = *timings;
c499144c 467
c8a5e4e8 468 mutex_unlock(&dpi.lock);
553c48cf 469}
c499144c 470EXPORT_SYMBOL(omapdss_dpi_set_timings);
553c48cf 471
69b2048f 472int dpi_check_timings(struct omap_dss_device *dssdev,
553c48cf
TV
473 struct omap_video_timings *timings)
474{
03a0d1e8 475 struct omap_overlay_manager *mgr = dpi.output.manager;
553c48cf
TV
476 int lck_div, pck_div;
477 unsigned long fck;
478 unsigned long pck;
100c8262
TV
479 struct dpi_clk_calc_ctx ctx;
480 bool ok;
553c48cf 481
8b095513 482 if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
553c48cf
TV
483 return -EINVAL;
484
485 if (timings->pixel_clock == 0)
486 return -EINVAL;
487
8a3db406 488 if (dpi.dsidev) {
100c8262
TV
489 ok = dpi_dsi_clk_calc(timings->pixel_clock * 1000, &ctx);
490 if (!ok)
491 return -EINVAL;
553c48cf 492
100c8262 493 fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
7636b3b4 494 } else {
100c8262
TV
495 ok = dpi_dss_clk_calc(timings->pixel_clock * 1000, &ctx);
496 if (!ok)
497 return -EINVAL;
553c48cf 498
100c8262 499 fck = ctx.dss_cinfo.fck;
553c48cf 500 }
7636b3b4 501
100c8262
TV
502 lck_div = ctx.dispc_cinfo.lck_div;
503 pck_div = ctx.dispc_cinfo.pck_div;
553c48cf
TV
504
505 pck = fck / lck_div / pck_div / 1000;
506
507 timings->pixel_clock = pck;
508
509 return 0;
510}
69b2048f 511EXPORT_SYMBOL(dpi_check_timings);
553c48cf 512
c6b393d4
AT
513void omapdss_dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
514{
515 mutex_lock(&dpi.lock);
516
517 dpi.data_lines = data_lines;
518
519 mutex_unlock(&dpi.lock);
520}
521EXPORT_SYMBOL(omapdss_dpi_set_data_lines);
522
94cf394b 523static int dpi_verify_dsi_pll(struct platform_device *dsidev)
6061675b
TV
524{
525 int r;
526
527 /* do initial setup with the PLL to see if it is operational */
528
529 r = dsi_runtime_get(dsidev);
530 if (r)
531 return r;
532
533 r = dsi_pll_init(dsidev, 0, 1);
534 if (r) {
535 dsi_runtime_put(dsidev);
536 return r;
537 }
538
539 dsi_pll_uninit(dsidev, true);
540 dsi_runtime_put(dsidev);
541
542 return 0;
543}
544
2eea5ae6
TV
545/*
546 * Return a hardcoded channel for the DPI output. This should work for
547 * current use cases, but this can be later expanded to either resolve
548 * the channel in some more dynamic manner, or get the channel as a user
549 * parameter.
550 */
551static enum omap_channel dpi_get_channel(void)
552{
553 switch (omapdss_get_version()) {
554 case OMAPDSS_VER_OMAP24xx:
555 case OMAPDSS_VER_OMAP34xx_ES1:
556 case OMAPDSS_VER_OMAP34xx_ES3:
557 case OMAPDSS_VER_OMAP3630:
558 case OMAPDSS_VER_AM35xx:
559 return OMAP_DSS_CHANNEL_LCD;
560
561 case OMAPDSS_VER_OMAP4430_ES1:
562 case OMAPDSS_VER_OMAP4430_ES2:
563 case OMAPDSS_VER_OMAP4:
564 return OMAP_DSS_CHANNEL_LCD2;
565
566 case OMAPDSS_VER_OMAP5:
567 return OMAP_DSS_CHANNEL_LCD3;
568
569 default:
570 DSSWARN("unsupported DSS version\n");
571 return OMAP_DSS_CHANNEL_LCD;
572 }
573}
574
94cf394b 575static int dpi_init_display(struct omap_dss_device *dssdev)
553c48cf 576{
0e8276ef
TV
577 struct platform_device *dsidev;
578
553c48cf
TV
579 DSSDBG("init_display\n");
580
195e672a
CM
581 if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) &&
582 dpi.vdds_dsi_reg == NULL) {
5f42f2ce 583 struct regulator *vdds_dsi;
553c48cf 584
5f42f2ce
TV
585 vdds_dsi = dss_get_vdds_dsi();
586
587 if (IS_ERR(vdds_dsi)) {
8a2cfea8 588 DSSERR("can't get VDDS_DSI regulator\n");
5f42f2ce 589 return PTR_ERR(vdds_dsi);
8a2cfea8 590 }
5f42f2ce
TV
591
592 dpi.vdds_dsi_reg = vdds_dsi;
8a2cfea8
TV
593 }
594
2eea5ae6 595 dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
6061675b 596
1de8e129 597 if (dsidev && dpi_verify_dsi_pll(dsidev)) {
0e8276ef
TV
598 dsidev = NULL;
599 DSSWARN("DSI PLL not operational\n");
a72b64b9
AT
600 }
601
0e8276ef
TV
602 if (dsidev)
603 DSSDBG("using DSI PLL for DPI clock\n");
604
605 dpi.dsidev = dsidev;
606
553c48cf
TV
607 return 0;
608}
609
94cf394b 610static struct omap_dss_device *dpi_find_dssdev(struct platform_device *pdev)
5f42f2ce 611{
35deca3d 612 struct omap_dss_board_info *pdata = pdev->dev.platform_data;
2bbcce5e 613 const char *def_disp_name = omapdss_get_default_display_name();
1521653c
TV
614 struct omap_dss_device *def_dssdev;
615 int i;
616
617 def_dssdev = NULL;
35deca3d
TV
618
619 for (i = 0; i < pdata->num_devices; ++i) {
620 struct omap_dss_device *dssdev = pdata->devices[i];
621
622 if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
623 continue;
624
1521653c
TV
625 if (def_dssdev == NULL)
626 def_dssdev = dssdev;
627
628 if (def_disp_name != NULL &&
629 strcmp(dssdev->name, def_disp_name) == 0) {
630 def_dssdev = dssdev;
631 break;
9d8232a7 632 }
1521653c 633 }
9d8232a7 634
1521653c
TV
635 return def_dssdev;
636}
637
bcb734d2 638static int dpi_probe_pdata(struct platform_device *dpidev)
1521653c 639{
5274484b 640 struct omap_dss_device *plat_dssdev;
1521653c
TV
641 struct omap_dss_device *dssdev;
642 int r;
643
5274484b 644 plat_dssdev = dpi_find_dssdev(dpidev);
1521653c 645
5274484b 646 if (!plat_dssdev)
bcb734d2 647 return 0;
5274484b
TV
648
649 dssdev = dss_alloc_and_init_device(&dpidev->dev);
1521653c 650 if (!dssdev)
bcb734d2 651 return -ENOMEM;
1521653c 652
5274484b
TV
653 dss_copy_device_pdata(dssdev, plat_dssdev);
654
1521653c
TV
655 r = dpi_init_display(dssdev);
656 if (r) {
657 DSSERR("device %s init failed: %d\n", dssdev->name, r);
5274484b 658 dss_put_device(dssdev);
bcb734d2 659 return r;
1521653c
TV
660 }
661
486c0e17
TV
662 r = omapdss_output_set_device(&dpi.output, dssdev);
663 if (r) {
664 DSSERR("failed to connect output to new device: %s\n",
665 dssdev->name);
666 dss_put_device(dssdev);
bcb734d2 667 return r;
486c0e17
TV
668 }
669
5274484b 670 r = dss_add_device(dssdev);
1521653c
TV
671 if (r) {
672 DSSERR("device %s register failed: %d\n", dssdev->name, r);
486c0e17 673 omapdss_output_unset_device(&dpi.output);
5274484b 674 dss_put_device(dssdev);
bcb734d2 675 return r;
35deca3d 676 }
bcb734d2
TV
677
678 return 0;
38f3daf6
TV
679}
680
94cf394b 681static void dpi_init_output(struct platform_device *pdev)
81b87f51
AT
682{
683 struct omap_dss_output *out = &dpi.output;
684
685 out->pdev = pdev;
686 out->id = OMAP_DSS_OUTPUT_DPI;
687 out->type = OMAP_DISPLAY_TYPE_DPI;
7286a08f 688 out->name = "dpi.0";
2eea5ae6 689 out->dispc_channel = dpi_get_channel();
81b87f51
AT
690
691 dss_register_output(out);
692}
693
694static void __exit dpi_uninit_output(struct platform_device *pdev)
695{
696 struct omap_dss_output *out = &dpi.output;
697
698 dss_unregister_output(out);
699}
700
94cf394b 701static int omap_dpi_probe(struct platform_device *pdev)
38f3daf6 702{
bcb734d2
TV
703 int r;
704
c8a5e4e8
AT
705 mutex_init(&dpi.lock);
706
81b87f51
AT
707 dpi_init_output(pdev);
708
bcb734d2
TV
709 r = dpi_probe_pdata(pdev);
710 if (r) {
711 dpi_uninit_output(pdev);
712 return r;
713 }
35deca3d 714
5f42f2ce
TV
715 return 0;
716}
717
6e7e8f06 718static int __exit omap_dpi_remove(struct platform_device *pdev)
553c48cf 719{
5274484b 720 dss_unregister_child_devices(&pdev->dev);
35deca3d 721
81b87f51
AT
722 dpi_uninit_output(pdev);
723
a57dd4fe 724 return 0;
553c48cf
TV
725}
726
a57dd4fe 727static struct platform_driver omap_dpi_driver = {
94cf394b 728 .probe = omap_dpi_probe,
6e7e8f06 729 .remove = __exit_p(omap_dpi_remove),
a57dd4fe
TV
730 .driver = {
731 .name = "omapdss_dpi",
732 .owner = THIS_MODULE,
733 },
734};
735
6e7e8f06 736int __init dpi_init_platform_driver(void)
a57dd4fe 737{
94cf394b 738 return platform_driver_register(&omap_dpi_driver);
a57dd4fe
TV
739}
740
6e7e8f06 741void __exit dpi_uninit_platform_driver(void)
a57dd4fe
TV
742{
743 platform_driver_unregister(&omap_dpi_driver);
744}
This page took 0.244069 seconds and 5 git commands to generate.