linux/drivers/video/fbdev/omap2/omapfb/dss/dpi.c
<<
>>
Prefs
   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#include <linux/string.h>
  33#include <linux/of.h>
  34#include <linux/clk.h>
  35#include <linux/component.h>
  36
  37#include <video/omapdss.h>
  38
  39#include "dss.h"
  40#include "dss_features.h"
  41
  42#define HSDIV_DISPC     0
  43
  44struct dpi_data {
  45        struct platform_device *pdev;
  46
  47        struct regulator *vdds_dsi_reg;
  48        struct dss_pll *pll;
  49
  50        struct mutex lock;
  51
  52        struct omap_video_timings timings;
  53        struct dss_lcd_mgr_config mgr_config;
  54        int data_lines;
  55
  56        struct omap_dss_device output;
  57
  58        bool port_initialized;
  59};
  60
  61static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
  62{
  63        return container_of(dssdev, struct dpi_data, output);
  64}
  65
  66/* only used in non-DT mode */
  67static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
  68{
  69        return dev_get_drvdata(&pdev->dev);
  70}
  71
  72static struct dss_pll *dpi_get_pll(enum omap_channel channel)
  73{
  74        /*
  75         * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
  76         * would also be used for DISPC fclk. Meaning, when the DPI output is
  77         * disabled, DISPC clock will be disabled, and TV out will stop.
  78         */
  79        switch (omapdss_get_version()) {
  80        case OMAPDSS_VER_OMAP24xx:
  81        case OMAPDSS_VER_OMAP34xx_ES1:
  82        case OMAPDSS_VER_OMAP34xx_ES3:
  83        case OMAPDSS_VER_OMAP3630:
  84        case OMAPDSS_VER_AM35xx:
  85        case OMAPDSS_VER_AM43xx:
  86                return NULL;
  87
  88        case OMAPDSS_VER_OMAP4430_ES1:
  89        case OMAPDSS_VER_OMAP4430_ES2:
  90        case OMAPDSS_VER_OMAP4:
  91                switch (channel) {
  92                case OMAP_DSS_CHANNEL_LCD:
  93                        return dss_pll_find("dsi0");
  94                case OMAP_DSS_CHANNEL_LCD2:
  95                        return dss_pll_find("dsi1");
  96                default:
  97                        return NULL;
  98                }
  99
 100        case OMAPDSS_VER_OMAP5:
 101                switch (channel) {
 102                case OMAP_DSS_CHANNEL_LCD:
 103                        return dss_pll_find("dsi0");
 104                case OMAP_DSS_CHANNEL_LCD3:
 105                        return dss_pll_find("dsi1");
 106                default:
 107                        return NULL;
 108                }
 109
 110        case OMAPDSS_VER_DRA7xx:
 111                switch (channel) {
 112                case OMAP_DSS_CHANNEL_LCD:
 113                case OMAP_DSS_CHANNEL_LCD2:
 114                        return dss_pll_find("video0");
 115                case OMAP_DSS_CHANNEL_LCD3:
 116                        return dss_pll_find("video1");
 117                default:
 118                        return NULL;
 119                }
 120
 121        default:
 122                return NULL;
 123        }
 124}
 125
 126static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
 127{
 128        switch (channel) {
 129        case OMAP_DSS_CHANNEL_LCD:
 130                return OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC;
 131        case OMAP_DSS_CHANNEL_LCD2:
 132                return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
 133        case OMAP_DSS_CHANNEL_LCD3:
 134                return OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC;
 135        default:
 136                /* this shouldn't happen */
 137                WARN_ON(1);
 138                return OMAP_DSS_CLK_SRC_FCK;
 139        }
 140}
 141
 142struct dpi_clk_calc_ctx {
 143        struct dss_pll *pll;
 144
 145        /* inputs */
 146
 147        unsigned long pck_min, pck_max;
 148
 149        /* outputs */
 150
 151        struct dss_pll_clock_info dsi_cinfo;
 152        unsigned long fck;
 153        struct dispc_clock_info dispc_cinfo;
 154};
 155
 156static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
 157                unsigned long pck, void *data)
 158{
 159        struct dpi_clk_calc_ctx *ctx = data;
 160
 161        /*
 162         * Odd dividers give us uneven duty cycle, causing problem when level
 163         * shifted. So skip all odd dividers when the pixel clock is on the
 164         * higher side.
 165         */
 166        if (ctx->pck_min >= 100000000) {
 167                if (lckd > 1 && lckd % 2 != 0)
 168                        return false;
 169
 170                if (pckd > 1 && pckd % 2 != 0)
 171                        return false;
 172        }
 173
 174        ctx->dispc_cinfo.lck_div = lckd;
 175        ctx->dispc_cinfo.pck_div = pckd;
 176        ctx->dispc_cinfo.lck = lck;
 177        ctx->dispc_cinfo.pck = pck;
 178
 179        return true;
 180}
 181
 182
 183static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
 184                void *data)
 185{
 186        struct dpi_clk_calc_ctx *ctx = data;
 187
 188        /*
 189         * Odd dividers give us uneven duty cycle, causing problem when level
 190         * shifted. So skip all odd dividers when the pixel clock is on the
 191         * higher side.
 192         */
 193        if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
 194                return false;
 195
 196        ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
 197        ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
 198
 199        return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
 200                        dpi_calc_dispc_cb, ctx);
 201}
 202
 203
 204static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
 205                unsigned long clkdco,
 206                void *data)
 207{
 208        struct dpi_clk_calc_ctx *ctx = data;
 209
 210        ctx->dsi_cinfo.n = n;
 211        ctx->dsi_cinfo.m = m;
 212        ctx->dsi_cinfo.fint = fint;
 213        ctx->dsi_cinfo.clkdco = clkdco;
 214
 215        return dss_pll_hsdiv_calc(ctx->pll, clkdco,
 216                ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
 217                dpi_calc_hsdiv_cb, ctx);
 218}
 219
 220static bool dpi_calc_dss_cb(unsigned long fck, void *data)
 221{
 222        struct dpi_clk_calc_ctx *ctx = data;
 223
 224        ctx->fck = fck;
 225
 226        return dispc_div_calc(fck, ctx->pck_min, ctx->pck_max,
 227                        dpi_calc_dispc_cb, ctx);
 228}
 229
 230static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
 231                struct dpi_clk_calc_ctx *ctx)
 232{
 233        unsigned long clkin;
 234        unsigned long pll_min, pll_max;
 235
 236        memset(ctx, 0, sizeof(*ctx));
 237        ctx->pll = dpi->pll;
 238        ctx->pck_min = pck - 1000;
 239        ctx->pck_max = pck + 1000;
 240
 241        pll_min = 0;
 242        pll_max = 0;
 243
 244        clkin = clk_get_rate(ctx->pll->clkin);
 245
 246        return dss_pll_calc(ctx->pll, clkin,
 247                        pll_min, pll_max,
 248                        dpi_calc_pll_cb, ctx);
 249}
 250
 251static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
 252{
 253        int i;
 254
 255        /*
 256         * DSS fck gives us very few possibilities, so finding a good pixel
 257         * clock may not be possible. We try multiple times to find the clock,
 258         * each time widening the pixel clock range we look for, up to
 259         * +/- ~15MHz.
 260         */
 261
 262        for (i = 0; i < 25; ++i) {
 263                bool ok;
 264
 265                memset(ctx, 0, sizeof(*ctx));
 266                if (pck > 1000 * i * i * i)
 267                        ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
 268                else
 269                        ctx->pck_min = 0;
 270                ctx->pck_max = pck + 1000 * i * i * i;
 271
 272                ok = dss_div_calc(pck, ctx->pck_min, dpi_calc_dss_cb, ctx);
 273                if (ok)
 274                        return ok;
 275        }
 276
 277        return false;
 278}
 279
 280
 281
 282static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
 283                unsigned long pck_req, unsigned long *fck, int *lck_div,
 284                int *pck_div)
 285{
 286        struct dpi_clk_calc_ctx ctx;
 287        int r;
 288        bool ok;
 289
 290        ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
 291        if (!ok)
 292                return -EINVAL;
 293
 294        r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
 295        if (r)
 296                return r;
 297
 298        dss_select_lcd_clk_source(channel,
 299                        dpi_get_alt_clk_src(channel));
 300
 301        dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 302
 303        *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
 304        *lck_div = ctx.dispc_cinfo.lck_div;
 305        *pck_div = ctx.dispc_cinfo.pck_div;
 306
 307        return 0;
 308}
 309
 310static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
 311                unsigned long *fck, int *lck_div, int *pck_div)
 312{
 313        struct dpi_clk_calc_ctx ctx;
 314        int r;
 315        bool ok;
 316
 317        ok = dpi_dss_clk_calc(pck_req, &ctx);
 318        if (!ok)
 319                return -EINVAL;
 320
 321        r = dss_set_fck_rate(ctx.fck);
 322        if (r)
 323                return r;
 324
 325        dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 326
 327        *fck = ctx.fck;
 328        *lck_div = ctx.dispc_cinfo.lck_div;
 329        *pck_div = ctx.dispc_cinfo.pck_div;
 330
 331        return 0;
 332}
 333
 334static int dpi_set_mode(struct dpi_data *dpi)
 335{
 336        struct omap_dss_device *out = &dpi->output;
 337        struct omap_overlay_manager *mgr = out->manager;
 338        struct omap_video_timings *t = &dpi->timings;
 339        int lck_div = 0, pck_div = 0;
 340        unsigned long fck = 0;
 341        unsigned long pck;
 342        int r = 0;
 343
 344        if (dpi->pll)
 345                r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
 346                                &lck_div, &pck_div);
 347        else
 348                r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
 349                                &lck_div, &pck_div);
 350        if (r)
 351                return r;
 352
 353        pck = fck / lck_div / pck_div;
 354
 355        if (pck != t->pixelclock) {
 356                DSSWARN("Could not find exact pixel clock. Requested %d Hz, got %lu Hz\n",
 357                        t->pixelclock, pck);
 358
 359                t->pixelclock = pck;
 360        }
 361
 362        dss_mgr_set_timings(mgr, t);
 363
 364        return 0;
 365}
 366
 367static void dpi_config_lcd_manager(struct dpi_data *dpi)
 368{
 369        struct omap_dss_device *out = &dpi->output;
 370        struct omap_overlay_manager *mgr = out->manager;
 371
 372        dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 373
 374        dpi->mgr_config.stallmode = false;
 375        dpi->mgr_config.fifohandcheck = false;
 376
 377        dpi->mgr_config.video_port_width = dpi->data_lines;
 378
 379        dpi->mgr_config.lcden_sig_polarity = 0;
 380
 381        dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
 382}
 383
 384static int dpi_display_enable(struct omap_dss_device *dssdev)
 385{
 386        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 387        struct omap_dss_device *out = &dpi->output;
 388        int r;
 389
 390        mutex_lock(&dpi->lock);
 391
 392        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
 393                DSSERR("no VDSS_DSI regulator\n");
 394                r = -ENODEV;
 395                goto err_no_reg;
 396        }
 397
 398        if (out->manager == NULL) {
 399                DSSERR("failed to enable display: no output/manager\n");
 400                r = -ENODEV;
 401                goto err_no_out_mgr;
 402        }
 403
 404        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
 405                r = regulator_enable(dpi->vdds_dsi_reg);
 406                if (r)
 407                        goto err_reg_enable;
 408        }
 409
 410        r = dispc_runtime_get();
 411        if (r)
 412                goto err_get_dispc;
 413
 414        r = dss_dpi_select_source(out->port_num, out->manager->id);
 415        if (r)
 416                goto err_src_sel;
 417
 418        if (dpi->pll) {
 419                r = dss_pll_enable(dpi->pll);
 420                if (r)
 421                        goto err_dsi_pll_init;
 422        }
 423
 424        r = dpi_set_mode(dpi);
 425        if (r)
 426                goto err_set_mode;
 427
 428        dpi_config_lcd_manager(dpi);
 429
 430        mdelay(2);
 431
 432        r = dss_mgr_enable(out->manager);
 433        if (r)
 434                goto err_mgr_enable;
 435
 436        mutex_unlock(&dpi->lock);
 437
 438        return 0;
 439
 440err_mgr_enable:
 441err_set_mode:
 442        if (dpi->pll)
 443                dss_pll_disable(dpi->pll);
 444err_dsi_pll_init:
 445err_src_sel:
 446        dispc_runtime_put();
 447err_get_dispc:
 448        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 449                regulator_disable(dpi->vdds_dsi_reg);
 450err_reg_enable:
 451err_no_out_mgr:
 452err_no_reg:
 453        mutex_unlock(&dpi->lock);
 454        return r;
 455}
 456
 457static void dpi_display_disable(struct omap_dss_device *dssdev)
 458{
 459        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 460        struct omap_overlay_manager *mgr = dpi->output.manager;
 461
 462        mutex_lock(&dpi->lock);
 463
 464        dss_mgr_disable(mgr);
 465
 466        if (dpi->pll) {
 467                dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
 468                dss_pll_disable(dpi->pll);
 469        }
 470
 471        dispc_runtime_put();
 472
 473        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 474                regulator_disable(dpi->vdds_dsi_reg);
 475
 476        mutex_unlock(&dpi->lock);
 477}
 478
 479static void dpi_set_timings(struct omap_dss_device *dssdev,
 480                struct omap_video_timings *timings)
 481{
 482        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 483
 484        DSSDBG("dpi_set_timings\n");
 485
 486        mutex_lock(&dpi->lock);
 487
 488        dpi->timings = *timings;
 489
 490        mutex_unlock(&dpi->lock);
 491}
 492
 493static void dpi_get_timings(struct omap_dss_device *dssdev,
 494                struct omap_video_timings *timings)
 495{
 496        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 497
 498        mutex_lock(&dpi->lock);
 499
 500        *timings = dpi->timings;
 501
 502        mutex_unlock(&dpi->lock);
 503}
 504
 505static int dpi_check_timings(struct omap_dss_device *dssdev,
 506                        struct omap_video_timings *timings)
 507{
 508        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 509        struct omap_overlay_manager *mgr = dpi->output.manager;
 510        int lck_div, pck_div;
 511        unsigned long fck;
 512        unsigned long pck;
 513        struct dpi_clk_calc_ctx ctx;
 514        bool ok;
 515
 516        if (mgr && !dispc_mgr_timings_ok(mgr->id, timings))
 517                return -EINVAL;
 518
 519        if (timings->pixelclock == 0)
 520                return -EINVAL;
 521
 522        if (dpi->pll) {
 523                ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
 524                if (!ok)
 525                        return -EINVAL;
 526
 527                fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
 528        } else {
 529                ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
 530                if (!ok)
 531                        return -EINVAL;
 532
 533                fck = ctx.fck;
 534        }
 535
 536        lck_div = ctx.dispc_cinfo.lck_div;
 537        pck_div = ctx.dispc_cinfo.pck_div;
 538
 539        pck = fck / lck_div / pck_div;
 540
 541        timings->pixelclock = pck;
 542
 543        return 0;
 544}
 545
 546static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
 547{
 548        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 549
 550        mutex_lock(&dpi->lock);
 551
 552        dpi->data_lines = data_lines;
 553
 554        mutex_unlock(&dpi->lock);
 555}
 556
 557static int dpi_verify_dsi_pll(struct dss_pll *pll)
 558{
 559        int r;
 560
 561        /* do initial setup with the PLL to see if it is operational */
 562
 563        r = dss_pll_enable(pll);
 564        if (r)
 565                return r;
 566
 567        dss_pll_disable(pll);
 568
 569        return 0;
 570}
 571
 572static int dpi_init_regulator(struct dpi_data *dpi)
 573{
 574        struct regulator *vdds_dsi;
 575
 576        if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 577                return 0;
 578
 579        if (dpi->vdds_dsi_reg)
 580                return 0;
 581
 582        vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
 583        if (IS_ERR(vdds_dsi)) {
 584                if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
 585                        DSSERR("can't get VDDS_DSI regulator\n");
 586                return PTR_ERR(vdds_dsi);
 587        }
 588
 589        dpi->vdds_dsi_reg = vdds_dsi;
 590
 591        return 0;
 592}
 593
 594static void dpi_init_pll(struct dpi_data *dpi)
 595{
 596        struct dss_pll *pll;
 597
 598        if (dpi->pll)
 599                return;
 600
 601        pll = dpi_get_pll(dpi->output.dispc_channel);
 602        if (!pll)
 603                return;
 604
 605        /* On DRA7 we need to set a mux to use the PLL */
 606        if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
 607                dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
 608
 609        if (dpi_verify_dsi_pll(pll)) {
 610                DSSWARN("DSI PLL not operational\n");
 611                return;
 612        }
 613
 614        dpi->pll = pll;
 615}
 616
 617/*
 618 * Return a hardcoded channel for the DPI output. This should work for
 619 * current use cases, but this can be later expanded to either resolve
 620 * the channel in some more dynamic manner, or get the channel as a user
 621 * parameter.
 622 */
 623static enum omap_channel dpi_get_channel(int port_num)
 624{
 625        switch (omapdss_get_version()) {
 626        case OMAPDSS_VER_OMAP24xx:
 627        case OMAPDSS_VER_OMAP34xx_ES1:
 628        case OMAPDSS_VER_OMAP34xx_ES3:
 629        case OMAPDSS_VER_OMAP3630:
 630        case OMAPDSS_VER_AM35xx:
 631        case OMAPDSS_VER_AM43xx:
 632                return OMAP_DSS_CHANNEL_LCD;
 633
 634        case OMAPDSS_VER_DRA7xx:
 635                switch (port_num) {
 636                case 2:
 637                        return OMAP_DSS_CHANNEL_LCD3;
 638                case 1:
 639                        return OMAP_DSS_CHANNEL_LCD2;
 640                case 0:
 641                default:
 642                        return OMAP_DSS_CHANNEL_LCD;
 643                }
 644
 645        case OMAPDSS_VER_OMAP4430_ES1:
 646        case OMAPDSS_VER_OMAP4430_ES2:
 647        case OMAPDSS_VER_OMAP4:
 648                return OMAP_DSS_CHANNEL_LCD2;
 649
 650        case OMAPDSS_VER_OMAP5:
 651                return OMAP_DSS_CHANNEL_LCD3;
 652
 653        default:
 654                DSSWARN("unsupported DSS version\n");
 655                return OMAP_DSS_CHANNEL_LCD;
 656        }
 657}
 658
 659static int dpi_connect(struct omap_dss_device *dssdev,
 660                struct omap_dss_device *dst)
 661{
 662        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 663        struct omap_overlay_manager *mgr;
 664        int r;
 665
 666        r = dpi_init_regulator(dpi);
 667        if (r)
 668                return r;
 669
 670        dpi_init_pll(dpi);
 671
 672        mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
 673        if (!mgr)
 674                return -ENODEV;
 675
 676        r = dss_mgr_connect(mgr, dssdev);
 677        if (r)
 678                return r;
 679
 680        r = omapdss_output_set_device(dssdev, dst);
 681        if (r) {
 682                DSSERR("failed to connect output to new device: %s\n",
 683                                dst->name);
 684                dss_mgr_disconnect(mgr, dssdev);
 685                return r;
 686        }
 687
 688        return 0;
 689}
 690
 691static void dpi_disconnect(struct omap_dss_device *dssdev,
 692                struct omap_dss_device *dst)
 693{
 694        WARN_ON(dst != dssdev->dst);
 695
 696        if (dst != dssdev->dst)
 697                return;
 698
 699        omapdss_output_unset_device(dssdev);
 700
 701        if (dssdev->manager)
 702                dss_mgr_disconnect(dssdev->manager, dssdev);
 703}
 704
 705static const struct omapdss_dpi_ops dpi_ops = {
 706        .connect = dpi_connect,
 707        .disconnect = dpi_disconnect,
 708
 709        .enable = dpi_display_enable,
 710        .disable = dpi_display_disable,
 711
 712        .check_timings = dpi_check_timings,
 713        .set_timings = dpi_set_timings,
 714        .get_timings = dpi_get_timings,
 715
 716        .set_data_lines = dpi_set_data_lines,
 717};
 718
 719static void dpi_init_output(struct platform_device *pdev)
 720{
 721        struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
 722        struct omap_dss_device *out = &dpi->output;
 723
 724        out->dev = &pdev->dev;
 725        out->id = OMAP_DSS_OUTPUT_DPI;
 726        out->output_type = OMAP_DISPLAY_TYPE_DPI;
 727        out->name = "dpi.0";
 728        out->dispc_channel = dpi_get_channel(0);
 729        out->ops.dpi = &dpi_ops;
 730        out->owner = THIS_MODULE;
 731
 732        omapdss_register_output(out);
 733}
 734
 735static void dpi_uninit_output(struct platform_device *pdev)
 736{
 737        struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
 738        struct omap_dss_device *out = &dpi->output;
 739
 740        omapdss_unregister_output(out);
 741}
 742
 743static void dpi_init_output_port(struct platform_device *pdev,
 744        struct device_node *port)
 745{
 746        struct dpi_data *dpi = port->data;
 747        struct omap_dss_device *out = &dpi->output;
 748        int r;
 749        u32 port_num;
 750
 751        r = of_property_read_u32(port, "reg", &port_num);
 752        if (r)
 753                port_num = 0;
 754
 755        switch (port_num) {
 756        case 2:
 757                out->name = "dpi.2";
 758                break;
 759        case 1:
 760                out->name = "dpi.1";
 761                break;
 762        case 0:
 763        default:
 764                out->name = "dpi.0";
 765                break;
 766        }
 767
 768        out->dev = &pdev->dev;
 769        out->id = OMAP_DSS_OUTPUT_DPI;
 770        out->output_type = OMAP_DISPLAY_TYPE_DPI;
 771        out->dispc_channel = dpi_get_channel(port_num);
 772        out->port_num = port_num;
 773        out->ops.dpi = &dpi_ops;
 774        out->owner = THIS_MODULE;
 775
 776        omapdss_register_output(out);
 777}
 778
 779static void dpi_uninit_output_port(struct device_node *port)
 780{
 781        struct dpi_data *dpi = port->data;
 782        struct omap_dss_device *out = &dpi->output;
 783
 784        omapdss_unregister_output(out);
 785}
 786
 787static int dpi_bind(struct device *dev, struct device *master, void *data)
 788{
 789        struct platform_device *pdev = to_platform_device(dev);
 790        struct dpi_data *dpi;
 791
 792        dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
 793        if (!dpi)
 794                return -ENOMEM;
 795
 796        dpi->pdev = pdev;
 797
 798        dev_set_drvdata(&pdev->dev, dpi);
 799
 800        mutex_init(&dpi->lock);
 801
 802        dpi_init_output(pdev);
 803
 804        return 0;
 805}
 806
 807static void dpi_unbind(struct device *dev, struct device *master, void *data)
 808{
 809        struct platform_device *pdev = to_platform_device(dev);
 810
 811        dpi_uninit_output(pdev);
 812}
 813
 814static const struct component_ops dpi_component_ops = {
 815        .bind   = dpi_bind,
 816        .unbind = dpi_unbind,
 817};
 818
 819static int dpi_probe(struct platform_device *pdev)
 820{
 821        return component_add(&pdev->dev, &dpi_component_ops);
 822}
 823
 824static int dpi_remove(struct platform_device *pdev)
 825{
 826        component_del(&pdev->dev, &dpi_component_ops);
 827        return 0;
 828}
 829
 830static struct platform_driver omap_dpi_driver = {
 831        .probe          = dpi_probe,
 832        .remove         = dpi_remove,
 833        .driver         = {
 834                .name   = "omapdss_dpi",
 835                .suppress_bind_attrs = true,
 836        },
 837};
 838
 839int __init dpi_init_platform_driver(void)
 840{
 841        return platform_driver_register(&omap_dpi_driver);
 842}
 843
 844void dpi_uninit_platform_driver(void)
 845{
 846        platform_driver_unregister(&omap_dpi_driver);
 847}
 848
 849int dpi_init_port(struct platform_device *pdev, struct device_node *port)
 850{
 851        struct dpi_data *dpi;
 852        struct device_node *ep;
 853        u32 datalines;
 854        int r;
 855
 856        dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
 857        if (!dpi)
 858                return -ENOMEM;
 859
 860        ep = omapdss_of_get_next_endpoint(port, NULL);
 861        if (!ep)
 862                return 0;
 863
 864        r = of_property_read_u32(ep, "data-lines", &datalines);
 865        if (r) {
 866                DSSERR("failed to parse datalines\n");
 867                goto err_datalines;
 868        }
 869
 870        dpi->data_lines = datalines;
 871
 872        of_node_put(ep);
 873
 874        dpi->pdev = pdev;
 875        port->data = dpi;
 876
 877        mutex_init(&dpi->lock);
 878
 879        dpi_init_output_port(pdev, port);
 880
 881        dpi->port_initialized = true;
 882
 883        return 0;
 884
 885err_datalines:
 886        of_node_put(ep);
 887
 888        return r;
 889}
 890
 891void dpi_uninit_port(struct device_node *port)
 892{
 893        struct dpi_data *dpi = port->data;
 894
 895        if (!dpi->port_initialized)
 896                return;
 897
 898        dpi_uninit_output_port(port);
 899}
 900