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