linux/drivers/video/exynos/exynos_mipi_dsi.c
<<
>>
Prefs
   1/* linux/drivers/video/exynos/exynos_mipi_dsi.c
   2 *
   3 * Samsung SoC MIPI-DSIM driver.
   4 *
   5 * Copyright (c) 2012 Samsung Electronics Co., Ltd
   6 *
   7 * InKi Dae, <inki.dae@samsung.com>
   8 * Donghwa Lee, <dh09.lee@samsung.com>
   9 *
  10 * This program is free software; you can redistribute it and/or modify
  11 * it under the terms of the GNU General Public License version 2 as
  12 * published by the Free Software Foundation.
  13*/
  14
  15#include <linux/module.h>
  16#include <linux/kernel.h>
  17#include <linux/errno.h>
  18#include <linux/clk.h>
  19#include <linux/mutex.h>
  20#include <linux/wait.h>
  21#include <linux/fs.h>
  22#include <linux/mm.h>
  23#include <linux/fb.h>
  24#include <linux/ctype.h>
  25#include <linux/platform_device.h>
  26#include <linux/io.h>
  27#include <linux/irq.h>
  28#include <linux/memory.h>
  29#include <linux/delay.h>
  30#include <linux/interrupt.h>
  31#include <linux/kthread.h>
  32#include <linux/notifier.h>
  33#include <linux/regulator/consumer.h>
  34#include <linux/pm_runtime.h>
  35
  36#include <video/exynos_mipi_dsim.h>
  37
  38#include <plat/fb.h>
  39
  40#include "exynos_mipi_dsi_common.h"
  41#include "exynos_mipi_dsi_lowlevel.h"
  42
  43struct mipi_dsim_ddi {
  44        int                             bus_id;
  45        struct list_head                list;
  46        struct mipi_dsim_lcd_device     *dsim_lcd_dev;
  47        struct mipi_dsim_lcd_driver     *dsim_lcd_drv;
  48};
  49
  50static LIST_HEAD(dsim_ddi_list);
  51
  52static DEFINE_MUTEX(mipi_dsim_lock);
  53
  54static struct mipi_dsim_platform_data *to_dsim_plat(struct platform_device
  55                                                        *pdev)
  56{
  57        return pdev->dev.platform_data;
  58}
  59
  60static struct regulator_bulk_data supplies[] = {
  61        { .supply = "vdd10", },
  62        { .supply = "vdd18", },
  63};
  64
  65static int exynos_mipi_regulator_enable(struct mipi_dsim_device *dsim)
  66{
  67        int ret;
  68
  69        mutex_lock(&dsim->lock);
  70        ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
  71        mutex_unlock(&dsim->lock);
  72
  73        return ret;
  74}
  75
  76static int exynos_mipi_regulator_disable(struct mipi_dsim_device *dsim)
  77{
  78        int ret;
  79
  80        mutex_lock(&dsim->lock);
  81        ret = regulator_bulk_disable(ARRAY_SIZE(supplies), supplies);
  82        mutex_unlock(&dsim->lock);
  83
  84        return ret;
  85}
  86
  87/* update all register settings to MIPI DSI controller. */
  88static void exynos_mipi_update_cfg(struct mipi_dsim_device *dsim)
  89{
  90        /*
  91         * data from Display controller(FIMD) is not transferred in video mode
  92         * but in case of command mode, all settings is not updated to
  93         * registers.
  94         */
  95        exynos_mipi_dsi_stand_by(dsim, 0);
  96
  97        exynos_mipi_dsi_init_dsim(dsim);
  98        exynos_mipi_dsi_init_link(dsim);
  99
 100        exynos_mipi_dsi_set_hs_enable(dsim);
 101
 102        /* set display timing. */
 103        exynos_mipi_dsi_set_display_mode(dsim, dsim->dsim_config);
 104
 105        /*
 106         * data from Display controller(FIMD) is transferred in video mode
 107         * but in case of command mode, all settigs is updated to registers.
 108         */
 109        exynos_mipi_dsi_stand_by(dsim, 1);
 110}
 111
 112static int exynos_mipi_dsi_early_blank_mode(struct mipi_dsim_device *dsim,
 113                int power)
 114{
 115        struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
 116        struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
 117
 118        switch (power) {
 119        case FB_BLANK_POWERDOWN:
 120                if (dsim->suspended)
 121                        return 0;
 122
 123                if (client_drv && client_drv->suspend)
 124                        client_drv->suspend(client_dev);
 125
 126                clk_disable(dsim->clock);
 127
 128                exynos_mipi_regulator_disable(dsim);
 129
 130                dsim->suspended = true;
 131
 132                break;
 133        default:
 134                break;
 135        }
 136
 137        return 0;
 138}
 139
 140static int exynos_mipi_dsi_blank_mode(struct mipi_dsim_device *dsim, int power)
 141{
 142        struct platform_device *pdev = to_platform_device(dsim->dev);
 143        struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
 144        struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
 145
 146        switch (power) {
 147        case FB_BLANK_UNBLANK:
 148                if (!dsim->suspended)
 149                        return 0;
 150
 151                /* lcd panel power on. */
 152                if (client_drv && client_drv->power_on)
 153                        client_drv->power_on(client_dev, 1);
 154
 155                exynos_mipi_regulator_disable(dsim);
 156
 157                /* enable MIPI-DSI PHY. */
 158                if (dsim->pd->phy_enable)
 159                        dsim->pd->phy_enable(pdev, true);
 160
 161                clk_enable(dsim->clock);
 162
 163                exynos_mipi_update_cfg(dsim);
 164
 165                /* set lcd panel sequence commands. */
 166                if (client_drv && client_drv->set_sequence)
 167                        client_drv->set_sequence(client_dev);
 168
 169                dsim->suspended = false;
 170
 171                break;
 172        case FB_BLANK_NORMAL:
 173                /* TODO. */
 174                break;
 175        default:
 176                break;
 177        }
 178
 179        return 0;
 180}
 181
 182int exynos_mipi_dsi_register_lcd_device(struct mipi_dsim_lcd_device *lcd_dev)
 183{
 184        struct mipi_dsim_ddi *dsim_ddi;
 185
 186        if (!lcd_dev->name) {
 187                pr_err("dsim_lcd_device name is NULL.\n");
 188                return -EFAULT;
 189        }
 190
 191        dsim_ddi = kzalloc(sizeof(struct mipi_dsim_ddi), GFP_KERNEL);
 192        if (!dsim_ddi) {
 193                pr_err("failed to allocate dsim_ddi object.\n");
 194                return -ENOMEM;
 195        }
 196
 197        dsim_ddi->dsim_lcd_dev = lcd_dev;
 198
 199        mutex_lock(&mipi_dsim_lock);
 200        list_add_tail(&dsim_ddi->list, &dsim_ddi_list);
 201        mutex_unlock(&mipi_dsim_lock);
 202
 203        return 0;
 204}
 205
 206struct mipi_dsim_ddi *exynos_mipi_dsi_find_lcd_device(struct mipi_dsim_lcd_driver *lcd_drv)
 207{
 208        struct mipi_dsim_ddi *dsim_ddi, *next;
 209        struct mipi_dsim_lcd_device *lcd_dev;
 210
 211        mutex_lock(&mipi_dsim_lock);
 212
 213        list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
 214                if (!dsim_ddi)
 215                        goto out;
 216
 217                lcd_dev = dsim_ddi->dsim_lcd_dev;
 218                if (!lcd_dev)
 219                        continue;
 220
 221                if ((strcmp(lcd_drv->name, lcd_dev->name)) == 0) {
 222                        /**
 223                         * bus_id would be used to identify
 224                         * connected bus.
 225                         */
 226                        dsim_ddi->bus_id = lcd_dev->bus_id;
 227                        mutex_unlock(&mipi_dsim_lock);
 228
 229                        return dsim_ddi;
 230                }
 231
 232                list_del(&dsim_ddi->list);
 233                kfree(dsim_ddi);
 234        }
 235
 236out:
 237        mutex_unlock(&mipi_dsim_lock);
 238
 239        return NULL;
 240}
 241
 242int exynos_mipi_dsi_register_lcd_driver(struct mipi_dsim_lcd_driver *lcd_drv)
 243{
 244        struct mipi_dsim_ddi *dsim_ddi;
 245
 246        if (!lcd_drv->name) {
 247                pr_err("dsim_lcd_driver name is NULL.\n");
 248                return -EFAULT;
 249        }
 250
 251        dsim_ddi = exynos_mipi_dsi_find_lcd_device(lcd_drv);
 252        if (!dsim_ddi) {
 253                pr_err("mipi_dsim_ddi object not found.\n");
 254                return -EFAULT;
 255        }
 256
 257        dsim_ddi->dsim_lcd_drv = lcd_drv;
 258
 259        pr_info("registered panel driver(%s) to mipi-dsi driver.\n",
 260                lcd_drv->name);
 261
 262        return 0;
 263
 264}
 265
 266struct mipi_dsim_ddi *exynos_mipi_dsi_bind_lcd_ddi(struct mipi_dsim_device *dsim,
 267                                                const char *name)
 268{
 269        struct mipi_dsim_ddi *dsim_ddi, *next;
 270        struct mipi_dsim_lcd_driver *lcd_drv;
 271        struct mipi_dsim_lcd_device *lcd_dev;
 272        int ret;
 273
 274        mutex_lock(&dsim->lock);
 275
 276        list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
 277                lcd_drv = dsim_ddi->dsim_lcd_drv;
 278                lcd_dev = dsim_ddi->dsim_lcd_dev;
 279                if (!lcd_drv || !lcd_dev ||
 280                        (dsim->id != dsim_ddi->bus_id))
 281                                continue;
 282
 283                dev_dbg(dsim->dev, "lcd_drv->id = %d, lcd_dev->id = %d\n",
 284                                lcd_drv->id, lcd_dev->id);
 285                dev_dbg(dsim->dev, "lcd_dev->bus_id = %d, dsim->id = %d\n",
 286                                lcd_dev->bus_id, dsim->id);
 287
 288                if ((strcmp(lcd_drv->name, name) == 0)) {
 289                        lcd_dev->master = dsim;
 290
 291                        lcd_dev->dev.parent = dsim->dev;
 292                        dev_set_name(&lcd_dev->dev, "%s", lcd_drv->name);
 293
 294                        ret = device_register(&lcd_dev->dev);
 295                        if (ret < 0) {
 296                                dev_err(dsim->dev,
 297                                        "can't register %s, status %d\n",
 298                                        dev_name(&lcd_dev->dev), ret);
 299                                mutex_unlock(&dsim->lock);
 300
 301                                return NULL;
 302                        }
 303
 304                        dsim->dsim_lcd_dev = lcd_dev;
 305                        dsim->dsim_lcd_drv = lcd_drv;
 306
 307                        mutex_unlock(&dsim->lock);
 308
 309                        return dsim_ddi;
 310                }
 311        }
 312
 313        mutex_unlock(&dsim->lock);
 314
 315        return NULL;
 316}
 317
 318/* define MIPI-DSI Master operations. */
 319static struct mipi_dsim_master_ops master_ops = {
 320        .cmd_read                       = exynos_mipi_dsi_rd_data,
 321        .cmd_write                      = exynos_mipi_dsi_wr_data,
 322        .get_dsim_frame_done            = exynos_mipi_dsi_get_frame_done_status,
 323        .clear_dsim_frame_done          = exynos_mipi_dsi_clear_frame_done,
 324        .set_early_blank_mode           = exynos_mipi_dsi_early_blank_mode,
 325        .set_blank_mode                 = exynos_mipi_dsi_blank_mode,
 326};
 327
 328static int exynos_mipi_dsi_probe(struct platform_device *pdev)
 329{
 330        struct resource *res;
 331        struct mipi_dsim_device *dsim;
 332        struct mipi_dsim_config *dsim_config;
 333        struct mipi_dsim_platform_data *dsim_pd;
 334        struct mipi_dsim_ddi *dsim_ddi;
 335        int ret = -EINVAL;
 336
 337        dsim = kzalloc(sizeof(struct mipi_dsim_device), GFP_KERNEL);
 338        if (!dsim) {
 339                dev_err(&pdev->dev, "failed to allocate dsim object.\n");
 340                return -ENOMEM;
 341        }
 342
 343        dsim->pd = to_dsim_plat(pdev);
 344        dsim->dev = &pdev->dev;
 345        dsim->id = pdev->id;
 346
 347        /* get mipi_dsim_platform_data. */
 348        dsim_pd = (struct mipi_dsim_platform_data *)dsim->pd;
 349        if (dsim_pd == NULL) {
 350                dev_err(&pdev->dev, "failed to get platform data for dsim.\n");
 351                goto err_clock_get;
 352        }
 353        /* get mipi_dsim_config. */
 354        dsim_config = dsim_pd->dsim_config;
 355        if (dsim_config == NULL) {
 356                dev_err(&pdev->dev, "failed to get dsim config data.\n");
 357                goto err_clock_get;
 358        }
 359
 360        dsim->dsim_config = dsim_config;
 361        dsim->master_ops = &master_ops;
 362
 363        mutex_init(&dsim->lock);
 364
 365        ret = regulator_bulk_get(&pdev->dev, ARRAY_SIZE(supplies), supplies);
 366        if (ret) {
 367                dev_err(&pdev->dev, "Failed to get regulators: %d\n", ret);
 368                goto err_clock_get;
 369        }
 370
 371        dsim->clock = clk_get(&pdev->dev, "dsim0");
 372        if (IS_ERR(dsim->clock)) {
 373                dev_err(&pdev->dev, "failed to get dsim clock source\n");
 374                goto err_clock_get;
 375        }
 376
 377        clk_enable(dsim->clock);
 378
 379        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 380        if (!res) {
 381                dev_err(&pdev->dev, "failed to get io memory region\n");
 382                goto err_platform_get;
 383        }
 384
 385        dsim->res = request_mem_region(res->start, resource_size(res),
 386                                        dev_name(&pdev->dev));
 387        if (!dsim->res) {
 388                dev_err(&pdev->dev, "failed to request io memory region\n");
 389                ret = -ENOMEM;
 390                goto err_mem_region;
 391        }
 392
 393        dsim->reg_base = ioremap(res->start, resource_size(res));
 394        if (!dsim->reg_base) {
 395                dev_err(&pdev->dev, "failed to remap io region\n");
 396                ret = -ENOMEM;
 397                goto err_ioremap;
 398        }
 399
 400        mutex_init(&dsim->lock);
 401
 402        /* bind lcd ddi matched with panel name. */
 403        dsim_ddi = exynos_mipi_dsi_bind_lcd_ddi(dsim, dsim_pd->lcd_panel_name);
 404        if (!dsim_ddi) {
 405                dev_err(&pdev->dev, "mipi_dsim_ddi object not found.\n");
 406                goto err_bind;
 407        }
 408
 409        dsim->irq = platform_get_irq(pdev, 0);
 410        if (dsim->irq < 0) {
 411                dev_err(&pdev->dev, "failed to request dsim irq resource\n");
 412                ret = -EINVAL;
 413                goto err_platform_get_irq;
 414        }
 415
 416        ret = request_irq(dsim->irq, exynos_mipi_dsi_interrupt_handler,
 417                        IRQF_SHARED, pdev->name, dsim);
 418        if (ret != 0) {
 419                dev_err(&pdev->dev, "failed to request dsim irq\n");
 420                ret = -EINVAL;
 421                goto err_bind;
 422        }
 423
 424        init_completion(&dsim_wr_comp);
 425        init_completion(&dsim_rd_comp);
 426
 427        /* enable interrupt */
 428        exynos_mipi_dsi_init_interrupt(dsim);
 429
 430        /* initialize mipi-dsi client(lcd panel). */
 431        if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->probe)
 432                dsim_ddi->dsim_lcd_drv->probe(dsim_ddi->dsim_lcd_dev);
 433
 434        /* in case that mipi got enabled at bootloader. */
 435        if (dsim_pd->enabled)
 436                goto out;
 437
 438        /* lcd panel power on. */
 439        if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->power_on)
 440                dsim_ddi->dsim_lcd_drv->power_on(dsim_ddi->dsim_lcd_dev, 1);
 441
 442        exynos_mipi_regulator_enable(dsim);
 443
 444        /* enable MIPI-DSI PHY. */
 445        if (dsim->pd->phy_enable)
 446                dsim->pd->phy_enable(pdev, true);
 447
 448        exynos_mipi_update_cfg(dsim);
 449
 450        /* set lcd panel sequence commands. */
 451        if (dsim_ddi->dsim_lcd_drv && dsim_ddi->dsim_lcd_drv->set_sequence)
 452                dsim_ddi->dsim_lcd_drv->set_sequence(dsim_ddi->dsim_lcd_dev);
 453
 454        dsim->suspended = false;
 455
 456out:
 457        platform_set_drvdata(pdev, dsim);
 458
 459        dev_dbg(&pdev->dev, "mipi-dsi driver(%s mode) has been probed.\n",
 460                (dsim_config->e_interface == DSIM_COMMAND) ?
 461                        "CPU" : "RGB");
 462
 463        return 0;
 464
 465err_bind:
 466        iounmap(dsim->reg_base);
 467
 468err_ioremap:
 469        release_mem_region(dsim->res->start, resource_size(dsim->res));
 470
 471err_mem_region:
 472        release_resource(dsim->res);
 473
 474err_platform_get:
 475        clk_disable(dsim->clock);
 476        clk_put(dsim->clock);
 477err_clock_get:
 478        kfree(dsim);
 479
 480err_platform_get_irq:
 481        return ret;
 482}
 483
 484static int __devexit exynos_mipi_dsi_remove(struct platform_device *pdev)
 485{
 486        struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
 487        struct mipi_dsim_ddi *dsim_ddi, *next;
 488        struct mipi_dsim_lcd_driver *dsim_lcd_drv;
 489
 490        iounmap(dsim->reg_base);
 491
 492        clk_disable(dsim->clock);
 493        clk_put(dsim->clock);
 494
 495        release_resource(dsim->res);
 496        release_mem_region(dsim->res->start, resource_size(dsim->res));
 497
 498        list_for_each_entry_safe(dsim_ddi, next, &dsim_ddi_list, list) {
 499                if (dsim_ddi) {
 500                        if (dsim->id != dsim_ddi->bus_id)
 501                                continue;
 502
 503                        dsim_lcd_drv = dsim_ddi->dsim_lcd_drv;
 504
 505                        if (dsim_lcd_drv->remove)
 506                                dsim_lcd_drv->remove(dsim_ddi->dsim_lcd_dev);
 507
 508                        kfree(dsim_ddi);
 509                }
 510        }
 511
 512        regulator_bulk_free(ARRAY_SIZE(supplies), supplies);
 513        kfree(dsim);
 514
 515        return 0;
 516}
 517
 518#ifdef CONFIG_PM
 519static int exynos_mipi_dsi_suspend(struct platform_device *pdev,
 520                pm_message_t state)
 521{
 522        struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
 523        struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
 524        struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
 525
 526        disable_irq(dsim->irq);
 527
 528        if (dsim->suspended)
 529                return 0;
 530
 531        if (client_drv && client_drv->suspend)
 532                client_drv->suspend(client_dev);
 533
 534        /* enable MIPI-DSI PHY. */
 535        if (dsim->pd->phy_enable)
 536                dsim->pd->phy_enable(pdev, false);
 537
 538        clk_disable(dsim->clock);
 539
 540        exynos_mipi_regulator_disable(dsim);
 541
 542        dsim->suspended = true;
 543
 544        return 0;
 545}
 546
 547static int exynos_mipi_dsi_resume(struct platform_device *pdev)
 548{
 549        struct mipi_dsim_device *dsim = platform_get_drvdata(pdev);
 550        struct mipi_dsim_lcd_driver *client_drv = dsim->dsim_lcd_drv;
 551        struct mipi_dsim_lcd_device *client_dev = dsim->dsim_lcd_dev;
 552
 553        enable_irq(dsim->irq);
 554
 555        if (!dsim->suspended)
 556                return 0;
 557
 558        /* lcd panel power on. */
 559        if (client_drv && client_drv->power_on)
 560                client_drv->power_on(client_dev, 1);
 561
 562        exynos_mipi_regulator_enable(dsim);
 563
 564        /* enable MIPI-DSI PHY. */
 565        if (dsim->pd->phy_enable)
 566                dsim->pd->phy_enable(pdev, true);
 567
 568        clk_enable(dsim->clock);
 569
 570        exynos_mipi_update_cfg(dsim);
 571
 572        /* set lcd panel sequence commands. */
 573        if (client_drv && client_drv->set_sequence)
 574                client_drv->set_sequence(client_dev);
 575
 576        dsim->suspended = false;
 577
 578        return 0;
 579}
 580#else
 581#define exynos_mipi_dsi_suspend NULL
 582#define exynos_mipi_dsi_resume NULL
 583#endif
 584
 585static struct platform_driver exynos_mipi_dsi_driver = {
 586        .probe = exynos_mipi_dsi_probe,
 587        .remove = __devexit_p(exynos_mipi_dsi_remove),
 588        .suspend = exynos_mipi_dsi_suspend,
 589        .resume = exynos_mipi_dsi_resume,
 590        .driver = {
 591                   .name = "exynos-mipi-dsim",
 592                   .owner = THIS_MODULE,
 593        },
 594};
 595
 596module_platform_driver(exynos_mipi_dsi_driver);
 597
 598MODULE_AUTHOR("InKi Dae <inki.dae@samsung.com>");
 599MODULE_DESCRIPTION("Samusung SoC MIPI-DSI driver");
 600MODULE_LICENSE("GPL");
 601