linux/drivers/gpu/drm/omapdrm/dss/dpi.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Copyright (C) 2009 Nokia Corporation
   4 * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
   5 *
   6 * Some code and ideas taken from drivers/video/omap/ driver
   7 * by Imre Deak.
   8 */
   9
  10#define DSS_SUBSYS_NAME "DPI"
  11
  12#include <linux/kernel.h>
  13#include <linux/delay.h>
  14#include <linux/export.h>
  15#include <linux/err.h>
  16#include <linux/errno.h>
  17#include <linux/platform_device.h>
  18#include <linux/regulator/consumer.h>
  19#include <linux/string.h>
  20#include <linux/of.h>
  21#include <linux/clk.h>
  22#include <linux/sys_soc.h>
  23
  24#include "omapdss.h"
  25#include "dss.h"
  26
  27struct dpi_data {
  28        struct platform_device *pdev;
  29        enum dss_model dss_model;
  30        struct dss_device *dss;
  31        unsigned int id;
  32
  33        struct regulator *vdds_dsi_reg;
  34        enum dss_clk_source clk_src;
  35        struct dss_pll *pll;
  36
  37        struct mutex lock;
  38
  39        struct dss_lcd_mgr_config mgr_config;
  40        unsigned long pixelclock;
  41        int data_lines;
  42
  43        struct omap_dss_device output;
  44};
  45
  46static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
  47{
  48        return container_of(dssdev, struct dpi_data, output);
  49}
  50
  51static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,
  52                                                  enum omap_channel channel)
  53{
  54        /*
  55         * Possible clock sources:
  56         * LCD1: FCK/PLL1_1/HDMI_PLL
  57         * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)
  58         * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)
  59         */
  60
  61        switch (channel) {
  62        case OMAP_DSS_CHANNEL_LCD:
  63        {
  64                if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1))
  65                        return DSS_CLK_SRC_PLL1_1;
  66                break;
  67        }
  68        case OMAP_DSS_CHANNEL_LCD2:
  69        {
  70                if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
  71                        return DSS_CLK_SRC_PLL1_3;
  72                if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3))
  73                        return DSS_CLK_SRC_PLL2_3;
  74                break;
  75        }
  76        case OMAP_DSS_CHANNEL_LCD3:
  77        {
  78                if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1))
  79                        return DSS_CLK_SRC_PLL2_1;
  80                if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
  81                        return DSS_CLK_SRC_PLL1_3;
  82                break;
  83        }
  84        default:
  85                break;
  86        }
  87
  88        return DSS_CLK_SRC_FCK;
  89}
  90
  91static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)
  92{
  93        enum omap_channel channel = dpi->output.dispc_channel;
  94
  95        /*
  96         * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
  97         * would also be used for DISPC fclk. Meaning, when the DPI output is
  98         * disabled, DISPC clock will be disabled, and TV out will stop.
  99         */
 100        switch (dpi->dss_model) {
 101        case DSS_MODEL_OMAP2:
 102        case DSS_MODEL_OMAP3:
 103                return DSS_CLK_SRC_FCK;
 104
 105        case DSS_MODEL_OMAP4:
 106                switch (channel) {
 107                case OMAP_DSS_CHANNEL_LCD:
 108                        return DSS_CLK_SRC_PLL1_1;
 109                case OMAP_DSS_CHANNEL_LCD2:
 110                        return DSS_CLK_SRC_PLL2_1;
 111                default:
 112                        return DSS_CLK_SRC_FCK;
 113                }
 114
 115        case DSS_MODEL_OMAP5:
 116                switch (channel) {
 117                case OMAP_DSS_CHANNEL_LCD:
 118                        return DSS_CLK_SRC_PLL1_1;
 119                case OMAP_DSS_CHANNEL_LCD3:
 120                        return DSS_CLK_SRC_PLL2_1;
 121                case OMAP_DSS_CHANNEL_LCD2:
 122                default:
 123                        return DSS_CLK_SRC_FCK;
 124                }
 125
 126        case DSS_MODEL_DRA7:
 127                return dpi_get_clk_src_dra7xx(dpi, channel);
 128
 129        default:
 130                return DSS_CLK_SRC_FCK;
 131        }
 132}
 133
 134struct dpi_clk_calc_ctx {
 135        struct dpi_data *dpi;
 136        unsigned int clkout_idx;
 137
 138        /* inputs */
 139
 140        unsigned long pck_min, pck_max;
 141
 142        /* outputs */
 143
 144        struct dss_pll_clock_info pll_cinfo;
 145        unsigned long fck;
 146        struct dispc_clock_info dispc_cinfo;
 147};
 148
 149static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
 150                unsigned long pck, void *data)
 151{
 152        struct dpi_clk_calc_ctx *ctx = data;
 153
 154        /*
 155         * Odd dividers give us uneven duty cycle, causing problem when level
 156         * shifted. So skip all odd dividers when the pixel clock is on the
 157         * higher side.
 158         */
 159        if (ctx->pck_min >= 100000000) {
 160                if (lckd > 1 && lckd % 2 != 0)
 161                        return false;
 162
 163                if (pckd > 1 && pckd % 2 != 0)
 164                        return false;
 165        }
 166
 167        ctx->dispc_cinfo.lck_div = lckd;
 168        ctx->dispc_cinfo.pck_div = pckd;
 169        ctx->dispc_cinfo.lck = lck;
 170        ctx->dispc_cinfo.pck = pck;
 171
 172        return true;
 173}
 174
 175
 176static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
 177                void *data)
 178{
 179        struct dpi_clk_calc_ctx *ctx = data;
 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(ctx->dpi->dss->dispc, dispc,
 185                              ctx->pck_min, ctx->pck_max,
 186                              dpi_calc_dispc_cb, ctx);
 187}
 188
 189
 190static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
 191                unsigned long clkdco,
 192                void *data)
 193{
 194        struct dpi_clk_calc_ctx *ctx = data;
 195
 196        ctx->pll_cinfo.n = n;
 197        ctx->pll_cinfo.m = m;
 198        ctx->pll_cinfo.fint = fint;
 199        ctx->pll_cinfo.clkdco = clkdco;
 200
 201        return dss_pll_hsdiv_calc_a(ctx->dpi->pll, clkdco,
 202                ctx->pck_min, dss_get_max_fck_rate(ctx->dpi->dss),
 203                dpi_calc_hsdiv_cb, ctx);
 204}
 205
 206static bool dpi_calc_dss_cb(unsigned long fck, void *data)
 207{
 208        struct dpi_clk_calc_ctx *ctx = data;
 209
 210        ctx->fck = fck;
 211
 212        return dispc_div_calc(ctx->dpi->dss->dispc, fck,
 213                              ctx->pck_min, ctx->pck_max,
 214                              dpi_calc_dispc_cb, ctx);
 215}
 216
 217static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,
 218                struct dpi_clk_calc_ctx *ctx)
 219{
 220        unsigned long clkin;
 221
 222        memset(ctx, 0, sizeof(*ctx));
 223        ctx->dpi = dpi;
 224        ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);
 225
 226        clkin = clk_get_rate(dpi->pll->clkin);
 227
 228        if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {
 229                unsigned long pll_min, pll_max;
 230
 231                ctx->pck_min = pck - 1000;
 232                ctx->pck_max = pck + 1000;
 233
 234                pll_min = 0;
 235                pll_max = 0;
 236
 237                return dss_pll_calc_a(ctx->dpi->pll, clkin,
 238                                pll_min, pll_max,
 239                                dpi_calc_pll_cb, ctx);
 240        } else { /* DSS_PLL_TYPE_B */
 241                dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);
 242
 243                ctx->dispc_cinfo.lck_div = 1;
 244                ctx->dispc_cinfo.pck_div = 1;
 245                ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];
 246                ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;
 247
 248                return true;
 249        }
 250}
 251
 252static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,
 253                             struct dpi_clk_calc_ctx *ctx)
 254{
 255        int i;
 256
 257        /*
 258         * DSS fck gives us very few possibilities, so finding a good pixel
 259         * clock may not be possible. We try multiple times to find the clock,
 260         * each time widening the pixel clock range we look for, up to
 261         * +/- ~15MHz.
 262         */
 263
 264        for (i = 0; i < 25; ++i) {
 265                bool ok;
 266
 267                memset(ctx, 0, sizeof(*ctx));
 268                ctx->dpi = dpi;
 269                if (pck > 1000 * i * i * i)
 270                        ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
 271                else
 272                        ctx->pck_min = 0;
 273                ctx->pck_max = pck + 1000 * i * i * i;
 274
 275                ok = dss_div_calc(dpi->dss, pck, ctx->pck_min,
 276                                  dpi_calc_dss_cb, ctx);
 277                if (ok)
 278                        return ok;
 279        }
 280
 281        return false;
 282}
 283
 284
 285
 286static int dpi_set_pll_clk(struct dpi_data *dpi, enum omap_channel channel,
 287                unsigned long pck_req, unsigned long *fck, int *lck_div,
 288                int *pck_div)
 289{
 290        struct dpi_clk_calc_ctx ctx;
 291        int r;
 292        bool ok;
 293
 294        ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);
 295        if (!ok)
 296                return -EINVAL;
 297
 298        r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);
 299        if (r)
 300                return r;
 301
 302        dss_select_lcd_clk_source(dpi->dss, channel, dpi->clk_src);
 303
 304        dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 305
 306        *fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
 307        *lck_div = ctx.dispc_cinfo.lck_div;
 308        *pck_div = ctx.dispc_cinfo.pck_div;
 309
 310        return 0;
 311}
 312
 313static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
 314                unsigned long *fck, int *lck_div, int *pck_div)
 315{
 316        struct dpi_clk_calc_ctx ctx;
 317        int r;
 318        bool ok;
 319
 320        ok = dpi_dss_clk_calc(dpi, pck_req, &ctx);
 321        if (!ok)
 322                return -EINVAL;
 323
 324        r = dss_set_fck_rate(dpi->dss, ctx.fck);
 325        if (r)
 326                return r;
 327
 328        dpi->mgr_config.clock_info = ctx.dispc_cinfo;
 329
 330        *fck = ctx.fck;
 331        *lck_div = ctx.dispc_cinfo.lck_div;
 332        *pck_div = ctx.dispc_cinfo.pck_div;
 333
 334        return 0;
 335}
 336
 337static int dpi_set_mode(struct dpi_data *dpi)
 338{
 339        int lck_div = 0, pck_div = 0;
 340        unsigned long fck = 0;
 341        int r = 0;
 342
 343        if (dpi->pll)
 344                r = dpi_set_pll_clk(dpi, dpi->output.dispc_channel,
 345                                    dpi->pixelclock, &fck, &lck_div, &pck_div);
 346        else
 347                r = dpi_set_dispc_clk(dpi, dpi->pixelclock, &fck,
 348                                &lck_div, &pck_div);
 349        if (r)
 350                return r;
 351
 352        return 0;
 353}
 354
 355static void dpi_config_lcd_manager(struct dpi_data *dpi)
 356{
 357        dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 358
 359        dpi->mgr_config.stallmode = false;
 360        dpi->mgr_config.fifohandcheck = false;
 361
 362        dpi->mgr_config.video_port_width = dpi->data_lines;
 363
 364        dpi->mgr_config.lcden_sig_polarity = 0;
 365
 366        dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
 367}
 368
 369static void dpi_display_enable(struct omap_dss_device *dssdev)
 370{
 371        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 372        struct omap_dss_device *out = &dpi->output;
 373        int r;
 374
 375        mutex_lock(&dpi->lock);
 376
 377        if (dpi->vdds_dsi_reg) {
 378                r = regulator_enable(dpi->vdds_dsi_reg);
 379                if (r)
 380                        goto err_reg_enable;
 381        }
 382
 383        r = dispc_runtime_get(dpi->dss->dispc);
 384        if (r)
 385                goto err_get_dispc;
 386
 387        r = dss_dpi_select_source(dpi->dss, dpi->id, out->dispc_channel);
 388        if (r)
 389                goto err_src_sel;
 390
 391        if (dpi->pll) {
 392                r = dss_pll_enable(dpi->pll);
 393                if (r)
 394                        goto err_pll_init;
 395        }
 396
 397        r = dpi_set_mode(dpi);
 398        if (r)
 399                goto err_set_mode;
 400
 401        dpi_config_lcd_manager(dpi);
 402
 403        mdelay(2);
 404
 405        r = dss_mgr_enable(&dpi->output);
 406        if (r)
 407                goto err_mgr_enable;
 408
 409        mutex_unlock(&dpi->lock);
 410
 411        return;
 412
 413err_mgr_enable:
 414err_set_mode:
 415        if (dpi->pll)
 416                dss_pll_disable(dpi->pll);
 417err_pll_init:
 418err_src_sel:
 419        dispc_runtime_put(dpi->dss->dispc);
 420err_get_dispc:
 421        if (dpi->vdds_dsi_reg)
 422                regulator_disable(dpi->vdds_dsi_reg);
 423err_reg_enable:
 424        mutex_unlock(&dpi->lock);
 425}
 426
 427static void dpi_display_disable(struct omap_dss_device *dssdev)
 428{
 429        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 430
 431        mutex_lock(&dpi->lock);
 432
 433        dss_mgr_disable(&dpi->output);
 434
 435        if (dpi->pll) {
 436                dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
 437                                          DSS_CLK_SRC_FCK);
 438                dss_pll_disable(dpi->pll);
 439        }
 440
 441        dispc_runtime_put(dpi->dss->dispc);
 442
 443        if (dpi->vdds_dsi_reg)
 444                regulator_disable(dpi->vdds_dsi_reg);
 445
 446        mutex_unlock(&dpi->lock);
 447}
 448
 449static void dpi_set_timings(struct omap_dss_device *dssdev,
 450                            const struct drm_display_mode *mode)
 451{
 452        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 453
 454        DSSDBG("dpi_set_timings\n");
 455
 456        mutex_lock(&dpi->lock);
 457
 458        dpi->pixelclock = mode->clock * 1000;
 459
 460        mutex_unlock(&dpi->lock);
 461}
 462
 463static int dpi_check_timings(struct omap_dss_device *dssdev,
 464                             struct drm_display_mode *mode)
 465{
 466        struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
 467        int lck_div, pck_div;
 468        unsigned long fck;
 469        unsigned long pck;
 470        struct dpi_clk_calc_ctx ctx;
 471        bool ok;
 472
 473        if (mode->hdisplay % 8 != 0)
 474                return -EINVAL;
 475
 476        if (mode->clock == 0)
 477                return -EINVAL;
 478
 479        if (dpi->pll) {
 480                ok = dpi_pll_clk_calc(dpi, mode->clock * 1000, &ctx);
 481                if (!ok)
 482                        return -EINVAL;
 483
 484                fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
 485        } else {
 486                ok = dpi_dss_clk_calc(dpi, mode->clock * 1000, &ctx);
 487                if (!ok)
 488                        return -EINVAL;
 489
 490                fck = ctx.fck;
 491        }
 492
 493        lck_div = ctx.dispc_cinfo.lck_div;
 494        pck_div = ctx.dispc_cinfo.pck_div;
 495
 496        pck = fck / lck_div / pck_div;
 497
 498        mode->clock = pck / 1000;
 499
 500        return 0;
 501}
 502
 503static int dpi_verify_pll(struct dss_pll *pll)
 504{
 505        int r;
 506
 507        /* do initial setup with the PLL to see if it is operational */
 508
 509        r = dss_pll_enable(pll);
 510        if (r)
 511                return r;
 512
 513        dss_pll_disable(pll);
 514
 515        return 0;
 516}
 517
 518static void dpi_init_pll(struct dpi_data *dpi)
 519{
 520        struct dss_pll *pll;
 521
 522        if (dpi->pll)
 523                return;
 524
 525        dpi->clk_src = dpi_get_clk_src(dpi);
 526
 527        pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);
 528        if (!pll)
 529                return;
 530
 531        if (dpi_verify_pll(pll)) {
 532                DSSWARN("PLL not operational\n");
 533                return;
 534        }
 535
 536        dpi->pll = pll;
 537}
 538
 539/*
 540 * Return a hardcoded channel for the DPI output. This should work for
 541 * current use cases, but this can be later expanded to either resolve
 542 * the channel in some more dynamic manner, or get the channel as a user
 543 * parameter.
 544 */
 545static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
 546{
 547        switch (dpi->dss_model) {
 548        case DSS_MODEL_OMAP2:
 549        case DSS_MODEL_OMAP3:
 550                return OMAP_DSS_CHANNEL_LCD;
 551
 552        case DSS_MODEL_DRA7:
 553                switch (dpi->id) {
 554                case 2:
 555                        return OMAP_DSS_CHANNEL_LCD3;
 556                case 1:
 557                        return OMAP_DSS_CHANNEL_LCD2;
 558                case 0:
 559                default:
 560                        return OMAP_DSS_CHANNEL_LCD;
 561                }
 562
 563        case DSS_MODEL_OMAP4:
 564                return OMAP_DSS_CHANNEL_LCD2;
 565
 566        case DSS_MODEL_OMAP5:
 567                return OMAP_DSS_CHANNEL_LCD3;
 568
 569        default:
 570                DSSWARN("unsupported DSS version\n");
 571                return OMAP_DSS_CHANNEL_LCD;
 572        }
 573}
 574
 575static int dpi_connect(struct omap_dss_device *src,
 576                       struct omap_dss_device *dst)
 577{
 578        struct dpi_data *dpi = dpi_get_data_from_dssdev(dst);
 579
 580        dpi_init_pll(dpi);
 581
 582        return omapdss_device_connect(dst->dss, dst, dst->next);
 583}
 584
 585static void dpi_disconnect(struct omap_dss_device *src,
 586                           struct omap_dss_device *dst)
 587{
 588        omapdss_device_disconnect(dst, dst->next);
 589}
 590
 591static const struct omap_dss_device_ops dpi_ops = {
 592        .connect = dpi_connect,
 593        .disconnect = dpi_disconnect,
 594
 595        .enable = dpi_display_enable,
 596        .disable = dpi_display_disable,
 597
 598        .check_timings = dpi_check_timings,
 599        .set_timings = dpi_set_timings,
 600};
 601
 602static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
 603{
 604        struct omap_dss_device *out = &dpi->output;
 605        u32 port_num = 0;
 606        int r;
 607
 608        of_property_read_u32(port, "reg", &port_num);
 609        dpi->id = port_num <= 2 ? port_num : 0;
 610
 611        switch (port_num) {
 612        case 2:
 613                out->name = "dpi.2";
 614                break;
 615        case 1:
 616                out->name = "dpi.1";
 617                break;
 618        case 0:
 619        default:
 620                out->name = "dpi.0";
 621                break;
 622        }
 623
 624        out->dev = &dpi->pdev->dev;
 625        out->id = OMAP_DSS_OUTPUT_DPI;
 626        out->type = OMAP_DISPLAY_TYPE_DPI;
 627        out->dispc_channel = dpi_get_channel(dpi);
 628        out->of_ports = BIT(port_num);
 629        out->ops = &dpi_ops;
 630        out->owner = THIS_MODULE;
 631
 632        r = omapdss_device_init_output(out);
 633        if (r < 0)
 634                return r;
 635
 636        omapdss_device_register(out);
 637
 638        return 0;
 639}
 640
 641static void dpi_uninit_output_port(struct device_node *port)
 642{
 643        struct dpi_data *dpi = port->data;
 644        struct omap_dss_device *out = &dpi->output;
 645
 646        omapdss_device_unregister(out);
 647        omapdss_device_cleanup_output(out);
 648}
 649
 650static const struct soc_device_attribute dpi_soc_devices[] = {
 651        { .machine = "OMAP3[456]*" },
 652        { .machine = "[AD]M37*" },
 653        { /* sentinel */ }
 654};
 655
 656static int dpi_init_regulator(struct dpi_data *dpi)
 657{
 658        struct regulator *vdds_dsi;
 659
 660        /*
 661         * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
 662         * DM37xx only.
 663         */
 664        if (!soc_device_match(dpi_soc_devices))
 665                return 0;
 666
 667        vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
 668        if (IS_ERR(vdds_dsi)) {
 669                if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
 670                        DSSERR("can't get VDDS_DSI regulator\n");
 671                return PTR_ERR(vdds_dsi);
 672        }
 673
 674        dpi->vdds_dsi_reg = vdds_dsi;
 675
 676        return 0;
 677}
 678
 679int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
 680                  struct device_node *port, enum dss_model dss_model)
 681{
 682        struct dpi_data *dpi;
 683        struct device_node *ep;
 684        u32 datalines;
 685        int r;
 686
 687        dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
 688        if (!dpi)
 689                return -ENOMEM;
 690
 691        ep = of_get_next_child(port, NULL);
 692        if (!ep)
 693                return 0;
 694
 695        r = of_property_read_u32(ep, "data-lines", &datalines);
 696        of_node_put(ep);
 697        if (r) {
 698                DSSERR("failed to parse datalines\n");
 699                return r;
 700        }
 701
 702        dpi->data_lines = datalines;
 703
 704        dpi->pdev = pdev;
 705        dpi->dss_model = dss_model;
 706        dpi->dss = dss;
 707        port->data = dpi;
 708
 709        mutex_init(&dpi->lock);
 710
 711        r = dpi_init_regulator(dpi);
 712        if (r)
 713                return r;
 714
 715        return dpi_init_output_port(dpi, port);
 716}
 717
 718void dpi_uninit_port(struct device_node *port)
 719{
 720        struct dpi_data *dpi = port->data;
 721
 722        if (!dpi)
 723                return;
 724
 725        dpi_uninit_output_port(port);
 726}
 727