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 <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        enum omap_channel channel = out->dispc_channel;
 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, channel, 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(channel, 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        enum omap_channel channel = out->dispc_channel;
 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(channel, &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        enum omap_channel channel = out->dispc_channel;
 389        int r;
 390
 391        mutex_lock(&dpi->lock);
 392
 393        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
 394                DSSERR("no VDSS_DSI regulator\n");
 395                r = -ENODEV;
 396                goto err_no_reg;
 397        }
 398
 399        if (!out->dispc_channel_connected) {
 400                DSSERR("failed to enable display: no output/manager\n");
 401                r = -ENODEV;
 402                goto err_no_out_mgr;
 403        }
 404
 405        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
 406                r = regulator_enable(dpi->vdds_dsi_reg);
 407                if (r)
 408                        goto err_reg_enable;
 409        }
 410
 411        r = dispc_runtime_get();
 412        if (r)
 413                goto err_get_dispc;
 414
 415        r = dss_dpi_select_source(out->port_num, channel);
 416        if (r)
 417                goto err_src_sel;
 418
 419        if (dpi->pll) {
 420                r = dss_pll_enable(dpi->pll);
 421                if (r)
 422                        goto err_dsi_pll_init;
 423        }
 424
 425        r = dpi_set_mode(dpi);
 426        if (r)
 427                goto err_set_mode;
 428
 429        dpi_config_lcd_manager(dpi);
 430
 431        mdelay(2);
 432
 433        r = dss_mgr_enable(channel);
 434        if (r)
 435                goto err_mgr_enable;
 436
 437        mutex_unlock(&dpi->lock);
 438
 439        return 0;
 440
 441err_mgr_enable:
 442err_set_mode:
 443        if (dpi->pll)
 444                dss_pll_disable(dpi->pll);
 445err_dsi_pll_init:
 446err_src_sel:
 447        dispc_runtime_put();
 448err_get_dispc:
 449        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 450                regulator_disable(dpi->vdds_dsi_reg);
 451err_reg_enable:
 452err_no_out_mgr:
 453err_no_reg:
 454        mutex_unlock(&dpi->lock);
 455        return r;
 456}
 457
 458static void dpi_display_disable(struct omap_dss_device *dssdev)
 459{
 460        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 461        enum omap_channel channel = dpi->output.dispc_channel;
 462
 463        mutex_lock(&dpi->lock);
 464
 465        dss_mgr_disable(channel);
 466
 467        if (dpi->pll) {
 468                dss_select_lcd_clk_source(channel, OMAP_DSS_CLK_SRC_FCK);
 469                dss_pll_disable(dpi->pll);
 470        }
 471
 472        dispc_runtime_put();
 473
 474        if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 475                regulator_disable(dpi->vdds_dsi_reg);
 476
 477        mutex_unlock(&dpi->lock);
 478}
 479
 480static void dpi_set_timings(struct omap_dss_device *dssdev,
 481                struct omap_video_timings *timings)
 482{
 483        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 484
 485        DSSDBG("dpi_set_timings\n");
 486
 487        mutex_lock(&dpi->lock);
 488
 489        dpi->timings = *timings;
 490
 491        mutex_unlock(&dpi->lock);
 492}
 493
 494static void dpi_get_timings(struct omap_dss_device *dssdev,
 495                struct omap_video_timings *timings)
 496{
 497        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 498
 499        mutex_lock(&dpi->lock);
 500
 501        *timings = dpi->timings;
 502
 503        mutex_unlock(&dpi->lock);
 504}
 505
 506static int dpi_check_timings(struct omap_dss_device *dssdev,
 507                        struct omap_video_timings *timings)
 508{
 509        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 510        enum omap_channel channel = dpi->output.dispc_channel;
 511        int lck_div, pck_div;
 512        unsigned long fck;
 513        unsigned long pck;
 514        struct dpi_clk_calc_ctx ctx;
 515        bool ok;
 516
 517        if (timings->x_res % 8 != 0)
 518                return -EINVAL;
 519
 520        if (!dispc_mgr_timings_ok(channel, timings))
 521                return -EINVAL;
 522
 523        if (timings->pixelclock == 0)
 524                return -EINVAL;
 525
 526        if (dpi->pll) {
 527                ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
 528                if (!ok)
 529                        return -EINVAL;
 530
 531                fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
 532        } else {
 533                ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
 534                if (!ok)
 535                        return -EINVAL;
 536
 537                fck = ctx.fck;
 538        }
 539
 540        lck_div = ctx.dispc_cinfo.lck_div;
 541        pck_div = ctx.dispc_cinfo.pck_div;
 542
 543        pck = fck / lck_div / pck_div;
 544
 545        timings->pixelclock = pck;
 546
 547        return 0;
 548}
 549
 550static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
 551{
 552        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 553
 554        mutex_lock(&dpi->lock);
 555
 556        dpi->data_lines = data_lines;
 557
 558        mutex_unlock(&dpi->lock);
 559}
 560
 561static int dpi_verify_dsi_pll(struct dss_pll *pll)
 562{
 563        int r;
 564
 565        /* do initial setup with the PLL to see if it is operational */
 566
 567        r = dss_pll_enable(pll);
 568        if (r)
 569                return r;
 570
 571        dss_pll_disable(pll);
 572
 573        return 0;
 574}
 575
 576static int dpi_init_regulator(struct dpi_data *dpi)
 577{
 578        struct regulator *vdds_dsi;
 579
 580        if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
 581                return 0;
 582
 583        if (dpi->vdds_dsi_reg)
 584                return 0;
 585
 586        vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
 587        if (IS_ERR(vdds_dsi)) {
 588                if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
 589                        DSSERR("can't get VDDS_DSI regulator\n");
 590                return PTR_ERR(vdds_dsi);
 591        }
 592
 593        dpi->vdds_dsi_reg = vdds_dsi;
 594
 595        return 0;
 596}
 597
 598static void dpi_init_pll(struct dpi_data *dpi)
 599{
 600        struct dss_pll *pll;
 601
 602        if (dpi->pll)
 603                return;
 604
 605        pll = dpi_get_pll(dpi->output.dispc_channel);
 606        if (!pll)
 607                return;
 608
 609        /* On DRA7 we need to set a mux to use the PLL */
 610        if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
 611                dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
 612
 613        if (dpi_verify_dsi_pll(pll)) {
 614                DSSWARN("DSI PLL not operational\n");
 615                return;
 616        }
 617
 618        dpi->pll = pll;
 619}
 620
 621/*
 622 * Return a hardcoded channel for the DPI output. This should work for
 623 * current use cases, but this can be later expanded to either resolve
 624 * the channel in some more dynamic manner, or get the channel as a user
 625 * parameter.
 626 */
 627static enum omap_channel dpi_get_channel(int port_num)
 628{
 629        switch (omapdss_get_version()) {
 630        case OMAPDSS_VER_OMAP24xx:
 631        case OMAPDSS_VER_OMAP34xx_ES1:
 632        case OMAPDSS_VER_OMAP34xx_ES3:
 633        case OMAPDSS_VER_OMAP3630:
 634        case OMAPDSS_VER_AM35xx:
 635        case OMAPDSS_VER_AM43xx:
 636                return OMAP_DSS_CHANNEL_LCD;
 637
 638        case OMAPDSS_VER_DRA7xx:
 639                switch (port_num) {
 640                case 2:
 641                        return OMAP_DSS_CHANNEL_LCD3;
 642                case 1:
 643                        return OMAP_DSS_CHANNEL_LCD2;
 644                case 0:
 645                default:
 646                        return OMAP_DSS_CHANNEL_LCD;
 647                }
 648
 649        case OMAPDSS_VER_OMAP4430_ES1:
 650        case OMAPDSS_VER_OMAP4430_ES2:
 651        case OMAPDSS_VER_OMAP4:
 652                return OMAP_DSS_CHANNEL_LCD2;
 653
 654        case OMAPDSS_VER_OMAP5:
 655                return OMAP_DSS_CHANNEL_LCD3;
 656
 657        default:
 658                DSSWARN("unsupported DSS version\n");
 659                return OMAP_DSS_CHANNEL_LCD;
 660        }
 661}
 662
 663static int dpi_connect(struct omap_dss_device *dssdev,
 664                struct omap_dss_device *dst)
 665{
 666        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 667        enum omap_channel channel = dpi->output.dispc_channel;
 668        int r;
 669
 670        r = dpi_init_regulator(dpi);
 671        if (r)
 672                return r;
 673
 674        dpi_init_pll(dpi);
 675
 676        r = dss_mgr_connect(channel, 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(channel, 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        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 695        enum omap_channel channel = dpi->output.dispc_channel;
 696
 697        WARN_ON(dst != dssdev->dst);
 698
 699        if (dst != dssdev->dst)
 700                return;
 701
 702        omapdss_output_unset_device(dssdev);
 703
 704        dss_mgr_disconnect(channel, dssdev);
 705}
 706
 707static const struct omapdss_dpi_ops dpi_ops = {
 708        .connect = dpi_connect,
 709        .disconnect = dpi_disconnect,
 710
 711        .enable = dpi_display_enable,
 712        .disable = dpi_display_disable,
 713
 714        .check_timings = dpi_check_timings,
 715        .set_timings = dpi_set_timings,
 716        .get_timings = dpi_get_timings,
 717
 718        .set_data_lines = dpi_set_data_lines,
 719};
 720
 721static void dpi_init_output(struct platform_device *pdev)
 722{
 723        struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
 724        struct omap_dss_device *out = &dpi->output;
 725
 726        out->dev = &pdev->dev;
 727        out->id = OMAP_DSS_OUTPUT_DPI;
 728        out->output_type = OMAP_DISPLAY_TYPE_DPI;
 729        out->name = "dpi.0";
 730        out->dispc_channel = dpi_get_channel(0);
 731        out->ops.dpi = &dpi_ops;
 732        out->owner = THIS_MODULE;
 733
 734        omapdss_register_output(out);
 735}
 736
 737static void dpi_uninit_output(struct platform_device *pdev)
 738{
 739        struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
 740        struct omap_dss_device *out = &dpi->output;
 741
 742        omapdss_unregister_output(out);
 743}
 744
 745static void dpi_init_output_port(struct platform_device *pdev,
 746        struct device_node *port)
 747{
 748        struct dpi_data *dpi = port->data;
 749        struct omap_dss_device *out = &dpi->output;
 750        int r;
 751        u32 port_num;
 752
 753        r = of_property_read_u32(port, "reg", &port_num);
 754        if (r)
 755                port_num = 0;
 756
 757        switch (port_num) {
 758        case 2:
 759                out->name = "dpi.2";
 760                break;
 761        case 1:
 762                out->name = "dpi.1";
 763                break;
 764        case 0:
 765        default:
 766                out->name = "dpi.0";
 767                break;
 768        }
 769
 770        out->dev = &pdev->dev;
 771        out->id = OMAP_DSS_OUTPUT_DPI;
 772        out->output_type = OMAP_DISPLAY_TYPE_DPI;
 773        out->dispc_channel = dpi_get_channel(port_num);
 774        out->port_num = port_num;
 775        out->ops.dpi = &dpi_ops;
 776        out->owner = THIS_MODULE;
 777
 778        omapdss_register_output(out);
 779}
 780
 781static void dpi_uninit_output_port(struct device_node *port)
 782{
 783        struct dpi_data *dpi = port->data;
 784        struct omap_dss_device *out = &dpi->output;
 785
 786        omapdss_unregister_output(out);
 787}
 788
 789static int dpi_bind(struct device *dev, struct device *master, void *data)
 790{
 791        struct platform_device *pdev = to_platform_device(dev);
 792        struct dpi_data *dpi;
 793
 794        dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
 795        if (!dpi)
 796                return -ENOMEM;
 797
 798        dpi->pdev = pdev;
 799
 800        dev_set_drvdata(&pdev->dev, dpi);
 801
 802        mutex_init(&dpi->lock);
 803
 804        dpi_init_output(pdev);
 805
 806        return 0;
 807}
 808
 809static void dpi_unbind(struct device *dev, struct device *master, void *data)
 810{
 811        struct platform_device *pdev = to_platform_device(dev);
 812
 813        dpi_uninit_output(pdev);
 814}
 815
 816static const struct component_ops dpi_component_ops = {
 817        .bind   = dpi_bind,
 818        .unbind = dpi_unbind,
 819};
 820
 821static int dpi_probe(struct platform_device *pdev)
 822{
 823        return component_add(&pdev->dev, &dpi_component_ops);
 824}
 825
 826static int dpi_remove(struct platform_device *pdev)
 827{
 828        component_del(&pdev->dev, &dpi_component_ops);
 829        return 0;
 830}
 831
 832static struct platform_driver omap_dpi_driver = {
 833        .probe          = dpi_probe,
 834        .remove         = dpi_remove,
 835        .driver         = {
 836                .name   = "omapdss_dpi",
 837                .suppress_bind_attrs = true,
 838        },
 839};
 840
 841int __init dpi_init_platform_driver(void)
 842{
 843        return platform_driver_register(&omap_dpi_driver);
 844}
 845
 846void dpi_uninit_platform_driver(void)
 847{
 848        platform_driver_unregister(&omap_dpi_driver);
 849}
 850
 851int dpi_init_port(struct platform_device *pdev, struct device_node *port)
 852{
 853        struct dpi_data *dpi;
 854        struct device_node *ep;
 855        u32 datalines;
 856        int r;
 857
 858        dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
 859        if (!dpi)
 860                return -ENOMEM;
 861
 862        ep = omapdss_of_get_next_endpoint(port, NULL);
 863        if (!ep)
 864                return 0;
 865
 866        r = of_property_read_u32(ep, "data-lines", &datalines);
 867        if (r) {
 868                DSSERR("failed to parse datalines\n");
 869                goto err_datalines;
 870        }
 871
 872        dpi->data_lines = datalines;
 873
 874        of_node_put(ep);
 875
 876        dpi->pdev = pdev;
 877        port->data = dpi;
 878
 879        mutex_init(&dpi->lock);
 880
 881        dpi_init_output_port(pdev, port);
 882
 883        dpi->port_initialized = true;
 884
 885        return 0;
 886
 887err_datalines:
 888        of_node_put(ep);
 889
 890        return r;
 891}
 892
 893void dpi_uninit_port(struct device_node *port)
 894{
 895        struct dpi_data *dpi = port->data;
 896
 897        if (!dpi->port_initialized)
 898                return;
 899
 900        dpi_uninit_output_port(port);
 901}
 902