Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) 2009 Nokia Corporation
0004  * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
0005  *
0006  * Some code and ideas taken from drivers/video/omap/ driver
0007  * by Imre Deak.
0008  */
0009 
0010 #define DSS_SUBSYS_NAME "DPI"
0011 
0012 #include <linux/clk.h>
0013 #include <linux/delay.h>
0014 #include <linux/err.h>
0015 #include <linux/errno.h>
0016 #include <linux/export.h>
0017 #include <linux/kernel.h>
0018 #include <linux/of.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/regulator/consumer.h>
0021 #include <linux/string.h>
0022 #include <linux/sys_soc.h>
0023 
0024 #include <drm/drm_bridge.h>
0025 
0026 #include "dss.h"
0027 #include "omapdss.h"
0028 
0029 struct dpi_data {
0030     struct platform_device *pdev;
0031     enum dss_model dss_model;
0032     struct dss_device *dss;
0033     unsigned int id;
0034 
0035     struct regulator *vdds_dsi_reg;
0036     enum dss_clk_source clk_src;
0037     struct dss_pll *pll;
0038 
0039     struct dss_lcd_mgr_config mgr_config;
0040     unsigned long pixelclock;
0041     int data_lines;
0042 
0043     struct omap_dss_device output;
0044     struct drm_bridge bridge;
0045 };
0046 
0047 #define drm_bridge_to_dpi(bridge) container_of(bridge, struct dpi_data, bridge)
0048 
0049 /* -----------------------------------------------------------------------------
0050  * Clock Handling and PLL
0051  */
0052 
0053 static enum dss_clk_source dpi_get_clk_src_dra7xx(struct dpi_data *dpi,
0054                           enum omap_channel channel)
0055 {
0056     /*
0057      * Possible clock sources:
0058      * LCD1: FCK/PLL1_1/HDMI_PLL
0059      * LCD2: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_3)
0060      * LCD3: FCK/PLL1_3/HDMI_PLL (DRA74x: PLL2_1)
0061      */
0062 
0063     switch (channel) {
0064     case OMAP_DSS_CHANNEL_LCD:
0065     {
0066         if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_1))
0067             return DSS_CLK_SRC_PLL1_1;
0068         break;
0069     }
0070     case OMAP_DSS_CHANNEL_LCD2:
0071     {
0072         if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
0073             return DSS_CLK_SRC_PLL1_3;
0074         if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_3))
0075             return DSS_CLK_SRC_PLL2_3;
0076         break;
0077     }
0078     case OMAP_DSS_CHANNEL_LCD3:
0079     {
0080         if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL2_1))
0081             return DSS_CLK_SRC_PLL2_1;
0082         if (dss_pll_find_by_src(dpi->dss, DSS_CLK_SRC_PLL1_3))
0083             return DSS_CLK_SRC_PLL1_3;
0084         break;
0085     }
0086     default:
0087         break;
0088     }
0089 
0090     return DSS_CLK_SRC_FCK;
0091 }
0092 
0093 static enum dss_clk_source dpi_get_clk_src(struct dpi_data *dpi)
0094 {
0095     enum omap_channel channel = dpi->output.dispc_channel;
0096 
0097     /*
0098      * XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
0099      * would also be used for DISPC fclk. Meaning, when the DPI output is
0100      * disabled, DISPC clock will be disabled, and TV out will stop.
0101      */
0102     switch (dpi->dss_model) {
0103     case DSS_MODEL_OMAP2:
0104     case DSS_MODEL_OMAP3:
0105         return DSS_CLK_SRC_FCK;
0106 
0107     case DSS_MODEL_OMAP4:
0108         switch (channel) {
0109         case OMAP_DSS_CHANNEL_LCD:
0110             return DSS_CLK_SRC_PLL1_1;
0111         case OMAP_DSS_CHANNEL_LCD2:
0112             return DSS_CLK_SRC_PLL2_1;
0113         default:
0114             return DSS_CLK_SRC_FCK;
0115         }
0116 
0117     case DSS_MODEL_OMAP5:
0118         switch (channel) {
0119         case OMAP_DSS_CHANNEL_LCD:
0120             return DSS_CLK_SRC_PLL1_1;
0121         case OMAP_DSS_CHANNEL_LCD3:
0122             return DSS_CLK_SRC_PLL2_1;
0123         case OMAP_DSS_CHANNEL_LCD2:
0124         default:
0125             return DSS_CLK_SRC_FCK;
0126         }
0127 
0128     case DSS_MODEL_DRA7:
0129         return dpi_get_clk_src_dra7xx(dpi, channel);
0130 
0131     default:
0132         return DSS_CLK_SRC_FCK;
0133     }
0134 }
0135 
0136 struct dpi_clk_calc_ctx {
0137     struct dpi_data *dpi;
0138     unsigned int clkout_idx;
0139 
0140     /* inputs */
0141 
0142     unsigned long pck_min, pck_max;
0143 
0144     /* outputs */
0145 
0146     struct dss_pll_clock_info pll_cinfo;
0147     unsigned long fck;
0148     struct dispc_clock_info dispc_cinfo;
0149 };
0150 
0151 static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
0152         unsigned long pck, void *data)
0153 {
0154     struct dpi_clk_calc_ctx *ctx = data;
0155 
0156     /*
0157      * Odd dividers give us uneven duty cycle, causing problem when level
0158      * shifted. So skip all odd dividers when the pixel clock is on the
0159      * higher side.
0160      */
0161     if (ctx->pck_min >= 100000000) {
0162         if (lckd > 1 && lckd % 2 != 0)
0163             return false;
0164 
0165         if (pckd > 1 && pckd % 2 != 0)
0166             return false;
0167     }
0168 
0169     ctx->dispc_cinfo.lck_div = lckd;
0170     ctx->dispc_cinfo.pck_div = pckd;
0171     ctx->dispc_cinfo.lck = lck;
0172     ctx->dispc_cinfo.pck = pck;
0173 
0174     return true;
0175 }
0176 
0177 
0178 static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
0179         void *data)
0180 {
0181     struct dpi_clk_calc_ctx *ctx = data;
0182 
0183     ctx->pll_cinfo.mX[ctx->clkout_idx] = m_dispc;
0184     ctx->pll_cinfo.clkout[ctx->clkout_idx] = dispc;
0185 
0186     return dispc_div_calc(ctx->dpi->dss->dispc, dispc,
0187                   ctx->pck_min, ctx->pck_max,
0188                   dpi_calc_dispc_cb, ctx);
0189 }
0190 
0191 
0192 static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
0193         unsigned long clkdco,
0194         void *data)
0195 {
0196     struct dpi_clk_calc_ctx *ctx = data;
0197 
0198     ctx->pll_cinfo.n = n;
0199     ctx->pll_cinfo.m = m;
0200     ctx->pll_cinfo.fint = fint;
0201     ctx->pll_cinfo.clkdco = clkdco;
0202 
0203     return dss_pll_hsdiv_calc_a(ctx->dpi->pll, clkdco,
0204         ctx->pck_min, dss_get_max_fck_rate(ctx->dpi->dss),
0205         dpi_calc_hsdiv_cb, ctx);
0206 }
0207 
0208 static bool dpi_calc_dss_cb(unsigned long fck, void *data)
0209 {
0210     struct dpi_clk_calc_ctx *ctx = data;
0211 
0212     ctx->fck = fck;
0213 
0214     return dispc_div_calc(ctx->dpi->dss->dispc, fck,
0215                   ctx->pck_min, ctx->pck_max,
0216                   dpi_calc_dispc_cb, ctx);
0217 }
0218 
0219 static bool dpi_pll_clk_calc(struct dpi_data *dpi, unsigned long pck,
0220         struct dpi_clk_calc_ctx *ctx)
0221 {
0222     unsigned long clkin;
0223 
0224     memset(ctx, 0, sizeof(*ctx));
0225     ctx->dpi = dpi;
0226     ctx->clkout_idx = dss_pll_get_clkout_idx_for_src(dpi->clk_src);
0227 
0228     clkin = clk_get_rate(dpi->pll->clkin);
0229 
0230     if (dpi->pll->hw->type == DSS_PLL_TYPE_A) {
0231         unsigned long pll_min, pll_max;
0232 
0233         ctx->pck_min = pck - 1000;
0234         ctx->pck_max = pck + 1000;
0235 
0236         pll_min = 0;
0237         pll_max = 0;
0238 
0239         return dss_pll_calc_a(ctx->dpi->pll, clkin,
0240                 pll_min, pll_max,
0241                 dpi_calc_pll_cb, ctx);
0242     } else { /* DSS_PLL_TYPE_B */
0243         dss_pll_calc_b(dpi->pll, clkin, pck, &ctx->pll_cinfo);
0244 
0245         ctx->dispc_cinfo.lck_div = 1;
0246         ctx->dispc_cinfo.pck_div = 1;
0247         ctx->dispc_cinfo.lck = ctx->pll_cinfo.clkout[0];
0248         ctx->dispc_cinfo.pck = ctx->dispc_cinfo.lck;
0249 
0250         return true;
0251     }
0252 }
0253 
0254 static bool dpi_dss_clk_calc(struct dpi_data *dpi, unsigned long pck,
0255                  struct dpi_clk_calc_ctx *ctx)
0256 {
0257     int i;
0258 
0259     /*
0260      * DSS fck gives us very few possibilities, so finding a good pixel
0261      * clock may not be possible. We try multiple times to find the clock,
0262      * each time widening the pixel clock range we look for, up to
0263      * +/- ~15MHz.
0264      */
0265 
0266     for (i = 0; i < 25; ++i) {
0267         bool ok;
0268 
0269         memset(ctx, 0, sizeof(*ctx));
0270         ctx->dpi = dpi;
0271         if (pck > 1000 * i * i * i)
0272             ctx->pck_min = max(pck - 1000 * i * i * i, 0lu);
0273         else
0274             ctx->pck_min = 0;
0275         ctx->pck_max = pck + 1000 * i * i * i;
0276 
0277         ok = dss_div_calc(dpi->dss, pck, ctx->pck_min,
0278                   dpi_calc_dss_cb, ctx);
0279         if (ok)
0280             return ok;
0281     }
0282 
0283     return false;
0284 }
0285 
0286 
0287 
0288 static int dpi_set_pll_clk(struct dpi_data *dpi, unsigned long pck_req)
0289 {
0290     struct dpi_clk_calc_ctx ctx;
0291     int r;
0292     bool ok;
0293 
0294     ok = dpi_pll_clk_calc(dpi, pck_req, &ctx);
0295     if (!ok)
0296         return -EINVAL;
0297 
0298     r = dss_pll_set_config(dpi->pll, &ctx.pll_cinfo);
0299     if (r)
0300         return r;
0301 
0302     dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
0303                   dpi->clk_src);
0304 
0305     dpi->mgr_config.clock_info = ctx.dispc_cinfo;
0306 
0307     return 0;
0308 }
0309 
0310 static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req)
0311 {
0312     struct dpi_clk_calc_ctx ctx;
0313     int r;
0314     bool ok;
0315 
0316     ok = dpi_dss_clk_calc(dpi, pck_req, &ctx);
0317     if (!ok)
0318         return -EINVAL;
0319 
0320     r = dss_set_fck_rate(dpi->dss, ctx.fck);
0321     if (r)
0322         return r;
0323 
0324     dpi->mgr_config.clock_info = ctx.dispc_cinfo;
0325 
0326     return 0;
0327 }
0328 
0329 static int dpi_set_mode(struct dpi_data *dpi)
0330 {
0331     int r;
0332 
0333     if (dpi->pll)
0334         r = dpi_set_pll_clk(dpi, dpi->pixelclock);
0335     else
0336         r = dpi_set_dispc_clk(dpi, dpi->pixelclock);
0337 
0338     return r;
0339 }
0340 
0341 static void dpi_config_lcd_manager(struct dpi_data *dpi)
0342 {
0343     dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
0344 
0345     dpi->mgr_config.stallmode = false;
0346     dpi->mgr_config.fifohandcheck = false;
0347 
0348     dpi->mgr_config.video_port_width = dpi->data_lines;
0349 
0350     dpi->mgr_config.lcden_sig_polarity = 0;
0351 
0352     dss_mgr_set_lcd_config(&dpi->output, &dpi->mgr_config);
0353 }
0354 
0355 static int dpi_clock_update(struct dpi_data *dpi, unsigned long *clock)
0356 {
0357     int lck_div, pck_div;
0358     unsigned long fck;
0359     struct dpi_clk_calc_ctx ctx;
0360 
0361     if (dpi->pll) {
0362         if (!dpi_pll_clk_calc(dpi, *clock, &ctx))
0363             return -EINVAL;
0364 
0365         fck = ctx.pll_cinfo.clkout[ctx.clkout_idx];
0366     } else {
0367         if (!dpi_dss_clk_calc(dpi, *clock, &ctx))
0368             return -EINVAL;
0369 
0370         fck = ctx.fck;
0371     }
0372 
0373     lck_div = ctx.dispc_cinfo.lck_div;
0374     pck_div = ctx.dispc_cinfo.pck_div;
0375 
0376     *clock = fck / lck_div / pck_div;
0377 
0378     return 0;
0379 }
0380 
0381 static int dpi_verify_pll(struct dss_pll *pll)
0382 {
0383     int r;
0384 
0385     /* do initial setup with the PLL to see if it is operational */
0386 
0387     r = dss_pll_enable(pll);
0388     if (r)
0389         return r;
0390 
0391     dss_pll_disable(pll);
0392 
0393     return 0;
0394 }
0395 
0396 static void dpi_init_pll(struct dpi_data *dpi)
0397 {
0398     struct dss_pll *pll;
0399 
0400     if (dpi->pll)
0401         return;
0402 
0403     dpi->clk_src = dpi_get_clk_src(dpi);
0404 
0405     pll = dss_pll_find_by_src(dpi->dss, dpi->clk_src);
0406     if (!pll)
0407         return;
0408 
0409     if (dpi_verify_pll(pll)) {
0410         DSSWARN("PLL not operational\n");
0411         return;
0412     }
0413 
0414     dpi->pll = pll;
0415 }
0416 
0417 /* -----------------------------------------------------------------------------
0418  * DRM Bridge Operations
0419  */
0420 
0421 static int dpi_bridge_attach(struct drm_bridge *bridge,
0422                  enum drm_bridge_attach_flags flags)
0423 {
0424     struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
0425 
0426     if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
0427         return -EINVAL;
0428 
0429     dpi_init_pll(dpi);
0430 
0431     return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
0432                  bridge, flags);
0433 }
0434 
0435 static enum drm_mode_status
0436 dpi_bridge_mode_valid(struct drm_bridge *bridge,
0437                const struct drm_display_info *info,
0438                const struct drm_display_mode *mode)
0439 {
0440     struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
0441     unsigned long clock = mode->clock * 1000;
0442     int ret;
0443 
0444     if (mode->hdisplay % 8 != 0)
0445         return MODE_BAD_WIDTH;
0446 
0447     if (mode->clock == 0)
0448         return MODE_NOCLOCK;
0449 
0450     ret = dpi_clock_update(dpi, &clock);
0451     if (ret < 0)
0452         return MODE_CLOCK_RANGE;
0453 
0454     return MODE_OK;
0455 }
0456 
0457 static bool dpi_bridge_mode_fixup(struct drm_bridge *bridge,
0458                    const struct drm_display_mode *mode,
0459                    struct drm_display_mode *adjusted_mode)
0460 {
0461     struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
0462     unsigned long clock = mode->clock * 1000;
0463     int ret;
0464 
0465     ret = dpi_clock_update(dpi, &clock);
0466     if (ret < 0)
0467         return false;
0468 
0469     adjusted_mode->clock = clock / 1000;
0470 
0471     return true;
0472 }
0473 
0474 static void dpi_bridge_mode_set(struct drm_bridge *bridge,
0475                  const struct drm_display_mode *mode,
0476                  const struct drm_display_mode *adjusted_mode)
0477 {
0478     struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
0479 
0480     dpi->pixelclock = adjusted_mode->clock * 1000;
0481 }
0482 
0483 static void dpi_bridge_enable(struct drm_bridge *bridge)
0484 {
0485     struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
0486     int r;
0487 
0488     if (dpi->vdds_dsi_reg) {
0489         r = regulator_enable(dpi->vdds_dsi_reg);
0490         if (r)
0491             return;
0492     }
0493 
0494     r = dispc_runtime_get(dpi->dss->dispc);
0495     if (r)
0496         goto err_get_dispc;
0497 
0498     r = dss_dpi_select_source(dpi->dss, dpi->id, dpi->output.dispc_channel);
0499     if (r)
0500         goto err_src_sel;
0501 
0502     if (dpi->pll) {
0503         r = dss_pll_enable(dpi->pll);
0504         if (r)
0505             goto err_pll_init;
0506     }
0507 
0508     r = dpi_set_mode(dpi);
0509     if (r)
0510         goto err_set_mode;
0511 
0512     dpi_config_lcd_manager(dpi);
0513 
0514     mdelay(2);
0515 
0516     r = dss_mgr_enable(&dpi->output);
0517     if (r)
0518         goto err_mgr_enable;
0519 
0520     return;
0521 
0522 err_mgr_enable:
0523 err_set_mode:
0524     if (dpi->pll)
0525         dss_pll_disable(dpi->pll);
0526 err_pll_init:
0527 err_src_sel:
0528     dispc_runtime_put(dpi->dss->dispc);
0529 err_get_dispc:
0530     if (dpi->vdds_dsi_reg)
0531         regulator_disable(dpi->vdds_dsi_reg);
0532 }
0533 
0534 static void dpi_bridge_disable(struct drm_bridge *bridge)
0535 {
0536     struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
0537 
0538     dss_mgr_disable(&dpi->output);
0539 
0540     if (dpi->pll) {
0541         dss_select_lcd_clk_source(dpi->dss, dpi->output.dispc_channel,
0542                       DSS_CLK_SRC_FCK);
0543         dss_pll_disable(dpi->pll);
0544     }
0545 
0546     dispc_runtime_put(dpi->dss->dispc);
0547 
0548     if (dpi->vdds_dsi_reg)
0549         regulator_disable(dpi->vdds_dsi_reg);
0550 }
0551 
0552 static const struct drm_bridge_funcs dpi_bridge_funcs = {
0553     .attach = dpi_bridge_attach,
0554     .mode_valid = dpi_bridge_mode_valid,
0555     .mode_fixup = dpi_bridge_mode_fixup,
0556     .mode_set = dpi_bridge_mode_set,
0557     .enable = dpi_bridge_enable,
0558     .disable = dpi_bridge_disable,
0559 };
0560 
0561 static void dpi_bridge_init(struct dpi_data *dpi)
0562 {
0563     dpi->bridge.funcs = &dpi_bridge_funcs;
0564     dpi->bridge.of_node = dpi->pdev->dev.of_node;
0565     dpi->bridge.type = DRM_MODE_CONNECTOR_DPI;
0566 
0567     drm_bridge_add(&dpi->bridge);
0568 }
0569 
0570 static void dpi_bridge_cleanup(struct dpi_data *dpi)
0571 {
0572     drm_bridge_remove(&dpi->bridge);
0573 }
0574 
0575 /* -----------------------------------------------------------------------------
0576  * Initialisation and Cleanup
0577  */
0578 
0579 /*
0580  * Return a hardcoded channel for the DPI output. This should work for
0581  * current use cases, but this can be later expanded to either resolve
0582  * the channel in some more dynamic manner, or get the channel as a user
0583  * parameter.
0584  */
0585 static enum omap_channel dpi_get_channel(struct dpi_data *dpi)
0586 {
0587     switch (dpi->dss_model) {
0588     case DSS_MODEL_OMAP2:
0589     case DSS_MODEL_OMAP3:
0590         return OMAP_DSS_CHANNEL_LCD;
0591 
0592     case DSS_MODEL_DRA7:
0593         switch (dpi->id) {
0594         case 2:
0595             return OMAP_DSS_CHANNEL_LCD3;
0596         case 1:
0597             return OMAP_DSS_CHANNEL_LCD2;
0598         case 0:
0599         default:
0600             return OMAP_DSS_CHANNEL_LCD;
0601         }
0602 
0603     case DSS_MODEL_OMAP4:
0604         return OMAP_DSS_CHANNEL_LCD2;
0605 
0606     case DSS_MODEL_OMAP5:
0607         return OMAP_DSS_CHANNEL_LCD3;
0608 
0609     default:
0610         DSSWARN("unsupported DSS version\n");
0611         return OMAP_DSS_CHANNEL_LCD;
0612     }
0613 }
0614 
0615 static int dpi_init_output_port(struct dpi_data *dpi, struct device_node *port)
0616 {
0617     struct omap_dss_device *out = &dpi->output;
0618     u32 port_num = 0;
0619     int r;
0620 
0621     dpi_bridge_init(dpi);
0622 
0623     of_property_read_u32(port, "reg", &port_num);
0624     dpi->id = port_num <= 2 ? port_num : 0;
0625 
0626     switch (port_num) {
0627     case 2:
0628         out->name = "dpi.2";
0629         break;
0630     case 1:
0631         out->name = "dpi.1";
0632         break;
0633     case 0:
0634     default:
0635         out->name = "dpi.0";
0636         break;
0637     }
0638 
0639     out->dev = &dpi->pdev->dev;
0640     out->id = OMAP_DSS_OUTPUT_DPI;
0641     out->type = OMAP_DISPLAY_TYPE_DPI;
0642     out->dispc_channel = dpi_get_channel(dpi);
0643     out->of_port = port_num;
0644 
0645     r = omapdss_device_init_output(out, &dpi->bridge);
0646     if (r < 0) {
0647         dpi_bridge_cleanup(dpi);
0648         return r;
0649     }
0650 
0651     omapdss_device_register(out);
0652 
0653     return 0;
0654 }
0655 
0656 static void dpi_uninit_output_port(struct device_node *port)
0657 {
0658     struct dpi_data *dpi = port->data;
0659     struct omap_dss_device *out = &dpi->output;
0660 
0661     omapdss_device_unregister(out);
0662     omapdss_device_cleanup_output(out);
0663 
0664     dpi_bridge_cleanup(dpi);
0665 }
0666 
0667 /* -----------------------------------------------------------------------------
0668  * Initialisation and Cleanup
0669  */
0670 
0671 static const struct soc_device_attribute dpi_soc_devices[] = {
0672     { .machine = "OMAP3[456]*" },
0673     { .machine = "[AD]M37*" },
0674     { /* sentinel */ }
0675 };
0676 
0677 static int dpi_init_regulator(struct dpi_data *dpi)
0678 {
0679     struct regulator *vdds_dsi;
0680 
0681     /*
0682      * The DPI uses the DSI VDDS on OMAP34xx, OMAP35xx, OMAP36xx, AM37xx and
0683      * DM37xx only.
0684      */
0685     if (!soc_device_match(dpi_soc_devices))
0686         return 0;
0687 
0688     vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
0689     if (IS_ERR(vdds_dsi)) {
0690         if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
0691             DSSERR("can't get VDDS_DSI regulator\n");
0692         return PTR_ERR(vdds_dsi);
0693     }
0694 
0695     dpi->vdds_dsi_reg = vdds_dsi;
0696 
0697     return 0;
0698 }
0699 
0700 int dpi_init_port(struct dss_device *dss, struct platform_device *pdev,
0701           struct device_node *port, enum dss_model dss_model)
0702 {
0703     struct dpi_data *dpi;
0704     struct device_node *ep;
0705     u32 datalines;
0706     int r;
0707 
0708     dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
0709     if (!dpi)
0710         return -ENOMEM;
0711 
0712     ep = of_get_next_child(port, NULL);
0713     if (!ep)
0714         return 0;
0715 
0716     r = of_property_read_u32(ep, "data-lines", &datalines);
0717     of_node_put(ep);
0718     if (r) {
0719         DSSERR("failed to parse datalines\n");
0720         return r;
0721     }
0722 
0723     dpi->data_lines = datalines;
0724 
0725     dpi->pdev = pdev;
0726     dpi->dss_model = dss_model;
0727     dpi->dss = dss;
0728     port->data = dpi;
0729 
0730     r = dpi_init_regulator(dpi);
0731     if (r)
0732         return r;
0733 
0734     return dpi_init_output_port(dpi, port);
0735 }
0736 
0737 void dpi_uninit_port(struct device_node *port)
0738 {
0739     struct dpi_data *dpi = port->data;
0740 
0741     if (!dpi)
0742         return;
0743 
0744     dpi_uninit_output_port(port);
0745 }