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