linux/drivers/video/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
  33#include <video/omapdss.h>
  34#include <plat/cpu.h>
  35
  36#include "dss.h"
  37
  38static struct {
  39        struct regulator *vdds_dsi_reg;
  40        struct platform_device *dsidev;
  41
  42        struct dss_lcd_mgr_config mgr_config;
  43} dpi;
  44
  45static struct platform_device *dpi_get_dsidev(enum omap_dss_clk_source clk)
  46{
  47        int dsi_module;
  48
  49        dsi_module = clk == OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ? 0 : 1;
  50
  51        return dsi_get_dsidev_from_id(dsi_module);
  52}
  53
  54static bool dpi_use_dsi_pll(struct omap_dss_device *dssdev)
  55{
  56        if (dssdev->clocks.dispc.dispc_fclk_src ==
  57                        OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
  58                        dssdev->clocks.dispc.dispc_fclk_src ==
  59                        OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC ||
  60                        dssdev->clocks.dispc.channel.lcd_clk_src ==
  61                        OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC ||
  62                        dssdev->clocks.dispc.channel.lcd_clk_src ==
  63                        OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC)
  64                return true;
  65        else
  66                return false;
  67}
  68
  69static int dpi_set_dsi_clk(struct omap_dss_device *dssdev,
  70                unsigned long pck_req, unsigned long *fck, int *lck_div,
  71                int *pck_div)
  72{
  73        struct dsi_clock_info dsi_cinfo;
  74        struct dispc_clock_info dispc_cinfo;
  75        int r;
  76
  77        r = dsi_pll_calc_clock_div_pck(dpi.dsidev, pck_req, &dsi_cinfo,
  78                        &dispc_cinfo);
  79        if (r)
  80                return r;
  81
  82        r = dsi_pll_set_clock_div(dpi.dsidev, &dsi_cinfo);
  83        if (r)
  84                return r;
  85
  86        dss_select_dispc_clk_source(dssdev->clocks.dispc.dispc_fclk_src);
  87
  88        dpi.mgr_config.clock_info = dispc_cinfo;
  89
  90        *fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
  91        *lck_div = dispc_cinfo.lck_div;
  92        *pck_div = dispc_cinfo.pck_div;
  93
  94        return 0;
  95}
  96
  97static int dpi_set_dispc_clk(struct omap_dss_device *dssdev,
  98                unsigned long pck_req, unsigned long *fck, int *lck_div,
  99                int *pck_div)
 100{
 101        struct dss_clock_info dss_cinfo;
 102        struct dispc_clock_info dispc_cinfo;
 103        int r;
 104
 105        r = dss_calc_clock_div(pck_req, &dss_cinfo, &dispc_cinfo);
 106        if (r)
 107                return r;
 108
 109        r = dss_set_clock_div(&dss_cinfo);
 110        if (r)
 111                return r;
 112
 113        dpi.mgr_config.clock_info = dispc_cinfo;
 114
 115        *fck = dss_cinfo.fck;
 116        *lck_div = dispc_cinfo.lck_div;
 117        *pck_div = dispc_cinfo.pck_div;
 118
 119        return 0;
 120}
 121
 122static int dpi_set_mode(struct omap_dss_device *dssdev)
 123{
 124        struct omap_video_timings *t = &dssdev->panel.timings;
 125        int lck_div = 0, pck_div = 0;
 126        unsigned long fck = 0;
 127        unsigned long pck;
 128        int r = 0;
 129
 130        if (dpi_use_dsi_pll(dssdev))
 131                r = dpi_set_dsi_clk(dssdev, t->pixel_clock * 1000, &fck,
 132                                &lck_div, &pck_div);
 133        else
 134                r = dpi_set_dispc_clk(dssdev, t->pixel_clock * 1000, &fck,
 135                                &lck_div, &pck_div);
 136        if (r)
 137                return r;
 138
 139        pck = fck / lck_div / pck_div / 1000;
 140
 141        if (pck != t->pixel_clock) {
 142                DSSWARN("Could not find exact pixel clock. "
 143                                "Requested %d kHz, got %lu kHz\n",
 144                                t->pixel_clock, pck);
 145
 146                t->pixel_clock = pck;
 147        }
 148
 149        dss_mgr_set_timings(dssdev->manager, t);
 150
 151        return 0;
 152}
 153
 154static void dpi_config_lcd_manager(struct omap_dss_device *dssdev)
 155{
 156        dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
 157
 158        dpi.mgr_config.stallmode = false;
 159        dpi.mgr_config.fifohandcheck = false;
 160
 161        dpi.mgr_config.video_port_width = dssdev->phy.dpi.data_lines;
 162
 163        dpi.mgr_config.lcden_sig_polarity = 0;
 164
 165        dss_mgr_set_lcd_config(dssdev->manager, &dpi.mgr_config);
 166}
 167
 168int omapdss_dpi_display_enable(struct omap_dss_device *dssdev)
 169{
 170        int r;
 171
 172        if (cpu_is_omap34xx() && !dpi.vdds_dsi_reg) {
 173                DSSERR("no VDSS_DSI regulator\n");
 174                return -ENODEV;
 175        }
 176
 177        if (dssdev->manager == NULL) {
 178                DSSERR("failed to enable display: no manager\n");
 179                return -ENODEV;
 180        }
 181
 182        r = omap_dss_start_device(dssdev);
 183        if (r) {
 184                DSSERR("failed to start device\n");
 185                goto err_start_dev;
 186        }
 187
 188        if (cpu_is_omap34xx()) {
 189                r = regulator_enable(dpi.vdds_dsi_reg);
 190                if (r)
 191                        goto err_reg_enable;
 192        }
 193
 194        r = dispc_runtime_get();
 195        if (r)
 196                goto err_get_dispc;
 197
 198        if (dpi_use_dsi_pll(dssdev)) {
 199                r = dsi_runtime_get(dpi.dsidev);
 200                if (r)
 201                        goto err_get_dsi;
 202
 203                r = dsi_pll_init(dpi.dsidev, 0, 1);
 204                if (r)
 205                        goto err_dsi_pll_init;
 206        }
 207
 208        r = dpi_set_mode(dssdev);
 209        if (r)
 210                goto err_set_mode;
 211
 212        dpi_config_lcd_manager(dssdev);
 213
 214        mdelay(2);
 215
 216        r = dss_mgr_enable(dssdev->manager);
 217        if (r)
 218                goto err_mgr_enable;
 219
 220        return 0;
 221
 222err_mgr_enable:
 223err_set_mode:
 224        if (dpi_use_dsi_pll(dssdev))
 225                dsi_pll_uninit(dpi.dsidev, true);
 226err_dsi_pll_init:
 227        if (dpi_use_dsi_pll(dssdev))
 228                dsi_runtime_put(dpi.dsidev);
 229err_get_dsi:
 230        dispc_runtime_put();
 231err_get_dispc:
 232        if (cpu_is_omap34xx())
 233                regulator_disable(dpi.vdds_dsi_reg);
 234err_reg_enable:
 235        omap_dss_stop_device(dssdev);
 236err_start_dev:
 237        return r;
 238}
 239EXPORT_SYMBOL(omapdss_dpi_display_enable);
 240
 241void omapdss_dpi_display_disable(struct omap_dss_device *dssdev)
 242{
 243        dss_mgr_disable(dssdev->manager);
 244
 245        if (dpi_use_dsi_pll(dssdev)) {
 246                dss_select_dispc_clk_source(OMAP_DSS_CLK_SRC_FCK);
 247                dsi_pll_uninit(dpi.dsidev, true);
 248                dsi_runtime_put(dpi.dsidev);
 249        }
 250
 251        dispc_runtime_put();
 252
 253        if (cpu_is_omap34xx())
 254                regulator_disable(dpi.vdds_dsi_reg);
 255
 256        omap_dss_stop_device(dssdev);
 257}
 258EXPORT_SYMBOL(omapdss_dpi_display_disable);
 259
 260void dpi_set_timings(struct omap_dss_device *dssdev,
 261                        struct omap_video_timings *timings)
 262{
 263        int r;
 264
 265        DSSDBG("dpi_set_timings\n");
 266        dssdev->panel.timings = *timings;
 267        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
 268                r = dispc_runtime_get();
 269                if (r)
 270                        return;
 271
 272                dpi_set_mode(dssdev);
 273
 274                dispc_runtime_put();
 275        } else {
 276                dss_mgr_set_timings(dssdev->manager, timings);
 277        }
 278}
 279EXPORT_SYMBOL(dpi_set_timings);
 280
 281int dpi_check_timings(struct omap_dss_device *dssdev,
 282                        struct omap_video_timings *timings)
 283{
 284        int r;
 285        int lck_div, pck_div;
 286        unsigned long fck;
 287        unsigned long pck;
 288        struct dispc_clock_info dispc_cinfo;
 289
 290        if (dss_mgr_check_timings(dssdev->manager, timings))
 291                return -EINVAL;
 292
 293        if (timings->pixel_clock == 0)
 294                return -EINVAL;
 295
 296        if (dpi_use_dsi_pll(dssdev)) {
 297                struct dsi_clock_info dsi_cinfo;
 298                r = dsi_pll_calc_clock_div_pck(dpi.dsidev,
 299                                timings->pixel_clock * 1000,
 300                                &dsi_cinfo, &dispc_cinfo);
 301
 302                if (r)
 303                        return r;
 304
 305                fck = dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
 306        } else {
 307                struct dss_clock_info dss_cinfo;
 308                r = dss_calc_clock_div(timings->pixel_clock * 1000,
 309                                &dss_cinfo, &dispc_cinfo);
 310
 311                if (r)
 312                        return r;
 313
 314                fck = dss_cinfo.fck;
 315        }
 316
 317        lck_div = dispc_cinfo.lck_div;
 318        pck_div = dispc_cinfo.pck_div;
 319
 320        pck = fck / lck_div / pck_div / 1000;
 321
 322        timings->pixel_clock = pck;
 323
 324        return 0;
 325}
 326EXPORT_SYMBOL(dpi_check_timings);
 327
 328static int __init dpi_init_display(struct omap_dss_device *dssdev)
 329{
 330        DSSDBG("init_display\n");
 331
 332        if (cpu_is_omap34xx() && dpi.vdds_dsi_reg == NULL) {
 333                struct regulator *vdds_dsi;
 334
 335                vdds_dsi = dss_get_vdds_dsi();
 336
 337                if (IS_ERR(vdds_dsi)) {
 338                        DSSERR("can't get VDDS_DSI regulator\n");
 339                        return PTR_ERR(vdds_dsi);
 340                }
 341
 342                dpi.vdds_dsi_reg = vdds_dsi;
 343        }
 344
 345        if (dpi_use_dsi_pll(dssdev)) {
 346                enum omap_dss_clk_source dispc_fclk_src =
 347                        dssdev->clocks.dispc.dispc_fclk_src;
 348                dpi.dsidev = dpi_get_dsidev(dispc_fclk_src);
 349        }
 350
 351        return 0;
 352}
 353
 354static void __init dpi_probe_pdata(struct platform_device *pdev)
 355{
 356        struct omap_dss_board_info *pdata = pdev->dev.platform_data;
 357        int i, r;
 358
 359        for (i = 0; i < pdata->num_devices; ++i) {
 360                struct omap_dss_device *dssdev = pdata->devices[i];
 361
 362                if (dssdev->type != OMAP_DISPLAY_TYPE_DPI)
 363                        continue;
 364
 365                r = dpi_init_display(dssdev);
 366                if (r) {
 367                        DSSERR("device %s init failed: %d\n", dssdev->name, r);
 368                        continue;
 369                }
 370
 371                r = omap_dss_register_device(dssdev, &pdev->dev, i);
 372                if (r)
 373                        DSSERR("device %s register failed: %d\n",
 374                                        dssdev->name, r);
 375        }
 376}
 377
 378static int __init omap_dpi_probe(struct platform_device *pdev)
 379{
 380        dpi_probe_pdata(pdev);
 381
 382        return 0;
 383}
 384
 385static int __exit omap_dpi_remove(struct platform_device *pdev)
 386{
 387        omap_dss_unregister_child_devices(&pdev->dev);
 388
 389        return 0;
 390}
 391
 392static struct platform_driver omap_dpi_driver = {
 393        .remove         = __exit_p(omap_dpi_remove),
 394        .driver         = {
 395                .name   = "omapdss_dpi",
 396                .owner  = THIS_MODULE,
 397        },
 398};
 399
 400int __init dpi_init_platform_driver(void)
 401{
 402        return platform_driver_probe(&omap_dpi_driver, omap_dpi_probe);
 403}
 404
 405void __exit dpi_uninit_platform_driver(void)
 406{
 407        platform_driver_unregister(&omap_dpi_driver);
 408}
 409