linux/drivers/video/omap2/displays/panel-generic-dpi.c
<<
>>
Prefs
   1/*
   2 * Generic DPI Panels support
   3 *
   4 * Copyright (C) 2010 Canonical Ltd.
   5 * Author: Bryan Wu <bryan.wu@canonical.com>
   6 *
   7 * LCD panel driver for Sharp LQ043T1DG01
   8 *
   9 * Copyright (C) 2009 Texas Instruments Inc
  10 * Author: Vaibhav Hiremath <hvaibhav@ti.com>
  11 *
  12 * LCD panel driver for Toppoly TDO35S
  13 *
  14 * Copyright (C) 2009 CompuLab, Ltd.
  15 * Author: Mike Rapoport <mike@compulab.co.il>
  16 *
  17 * Copyright (C) 2008 Nokia Corporation
  18 * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
  19 *
  20 * This program is free software; you can redistribute it and/or modify it
  21 * under the terms of the GNU General Public License version 2 as published by
  22 * the Free Software Foundation.
  23 *
  24 * This program is distributed in the hope that it will be useful, but WITHOUT
  25 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  26 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
  27 * more details.
  28 *
  29 * You should have received a copy of the GNU General Public License along with
  30 * this program.  If not, see <http://www.gnu.org/licenses/>.
  31 */
  32
  33#include <linux/module.h>
  34#include <linux/delay.h>
  35#include <linux/slab.h>
  36#include <linux/gpio.h>
  37#include <video/omapdss.h>
  38
  39#include <video/omap-panel-data.h>
  40
  41struct panel_config {
  42        struct omap_video_timings timings;
  43
  44        int power_on_delay;
  45        int power_off_delay;
  46
  47        /*
  48         * Used to match device to panel configuration
  49         * when use generic panel driver
  50         */
  51        const char *name;
  52};
  53
  54/* Panel configurations */
  55static struct panel_config generic_dpi_panels[] = {
  56        /* Sharp LQ043T1DG01 */
  57        {
  58                {
  59                        .x_res          = 480,
  60                        .y_res          = 272,
  61
  62                        .pixel_clock    = 9000,
  63
  64                        .hsw            = 42,
  65                        .hfp            = 3,
  66                        .hbp            = 2,
  67
  68                        .vsw            = 11,
  69                        .vfp            = 3,
  70                        .vbp            = 2,
  71
  72                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  73                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  74                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
  75                        .de_level       = OMAPDSS_SIG_ACTIVE_LOW,
  76                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
  77                },
  78                .power_on_delay         = 50,
  79                .power_off_delay        = 100,
  80                .name                   = "sharp_lq",
  81        },
  82
  83        /* Sharp LS037V7DW01 */
  84        {
  85                {
  86                        .x_res          = 480,
  87                        .y_res          = 640,
  88
  89                        .pixel_clock    = 19200,
  90
  91                        .hsw            = 2,
  92                        .hfp            = 1,
  93                        .hbp            = 28,
  94
  95                        .vsw            = 1,
  96                        .vfp            = 1,
  97                        .vbp            = 1,
  98
  99                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 100                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 101                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 102                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 103                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 104                },
 105                .power_on_delay         = 50,
 106                .power_off_delay        = 100,
 107                .name                   = "sharp_ls",
 108        },
 109
 110        /* Toppoly TDO35S */
 111        {
 112                {
 113                        .x_res          = 480,
 114                        .y_res          = 640,
 115
 116                        .pixel_clock    = 26000,
 117
 118                        .hfp            = 104,
 119                        .hsw            = 8,
 120                        .hbp            = 8,
 121
 122                        .vfp            = 4,
 123                        .vsw            = 2,
 124                        .vbp            = 2,
 125
 126                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 127                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 128                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 129                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 130                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 131                },
 132                .power_on_delay         = 0,
 133                .power_off_delay        = 0,
 134                .name                   = "toppoly_tdo35s",
 135        },
 136
 137        /* Samsung LTE430WQ-F0C */
 138        {
 139                {
 140                        .x_res          = 480,
 141                        .y_res          = 272,
 142
 143                        .pixel_clock    = 9200,
 144
 145                        .hfp            = 8,
 146                        .hsw            = 41,
 147                        .hbp            = 45 - 41,
 148
 149                        .vfp            = 4,
 150                        .vsw            = 10,
 151                        .vbp            = 12 - 10,
 152
 153                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 154                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 155                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 156                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 157                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 158                },
 159                .power_on_delay         = 0,
 160                .power_off_delay        = 0,
 161                .name                   = "samsung_lte430wq_f0c",
 162        },
 163
 164        /* Seiko 70WVW1TZ3Z3 */
 165        {
 166                {
 167                        .x_res          = 800,
 168                        .y_res          = 480,
 169
 170                        .pixel_clock    = 33000,
 171
 172                        .hsw            = 128,
 173                        .hfp            = 10,
 174                        .hbp            = 10,
 175
 176                        .vsw            = 2,
 177                        .vfp            = 4,
 178                        .vbp            = 11,
 179
 180                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 181                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 182                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 183                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 184                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 185                },
 186                .power_on_delay         = 0,
 187                .power_off_delay        = 0,
 188                .name                   = "seiko_70wvw1tz3",
 189        },
 190
 191        /* Powertip PH480272T */
 192        {
 193                {
 194                        .x_res          = 480,
 195                        .y_res          = 272,
 196
 197                        .pixel_clock    = 9000,
 198
 199                        .hsw            = 40,
 200                        .hfp            = 2,
 201                        .hbp            = 2,
 202
 203                        .vsw            = 10,
 204                        .vfp            = 2,
 205                        .vbp            = 2,
 206
 207                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 208                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 209                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 210                        .de_level       = OMAPDSS_SIG_ACTIVE_LOW,
 211                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 212                },
 213                .power_on_delay         = 0,
 214                .power_off_delay        = 0,
 215                .name                   = "powertip_ph480272t",
 216        },
 217
 218        /* Innolux AT070TN83 */
 219        {
 220                {
 221                        .x_res          = 800,
 222                        .y_res          = 480,
 223
 224                        .pixel_clock    = 40000,
 225
 226                        .hsw            = 48,
 227                        .hfp            = 1,
 228                        .hbp            = 1,
 229
 230                        .vsw            = 3,
 231                        .vfp            = 12,
 232                        .vbp            = 25,
 233
 234                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 235                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 236                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 237                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 238                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 239                },
 240                .power_on_delay         = 0,
 241                .power_off_delay        = 0,
 242                .name                   = "innolux_at070tn83",
 243        },
 244
 245        /* NEC NL2432DR22-11B */
 246        {
 247                {
 248                        .x_res          = 240,
 249                        .y_res          = 320,
 250
 251                        .pixel_clock    = 5400,
 252
 253                        .hsw            = 3,
 254                        .hfp            = 3,
 255                        .hbp            = 39,
 256
 257                        .vsw            = 1,
 258                        .vfp            = 2,
 259                        .vbp            = 7,
 260
 261                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 262                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 263                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 264                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 265                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 266                },
 267                .name                   = "nec_nl2432dr22-11b",
 268        },
 269
 270        /* Unknown panel used in OMAP H4 */
 271        {
 272                {
 273                        .x_res          = 240,
 274                        .y_res          = 320,
 275
 276                        .pixel_clock    = 6250,
 277
 278                        .hsw            = 15,
 279                        .hfp            = 15,
 280                        .hbp            = 60,
 281
 282                        .vsw            = 1,
 283                        .vfp            = 1,
 284                        .vbp            = 1,
 285
 286                        .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 287                        .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 288                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 289                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 290                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 291                },
 292                .name                   = "h4",
 293        },
 294
 295        /* FocalTech ETM070003DH6 */
 296        {
 297                {
 298                        .x_res          = 800,
 299                        .y_res          = 480,
 300
 301                        .pixel_clock    = 28000,
 302
 303                        .hsw            = 48,
 304                        .hfp            = 40,
 305                        .hbp            = 40,
 306
 307                        .vsw            = 3,
 308                        .vfp            = 13,
 309                        .vbp            = 29,
 310
 311                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 312                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 313                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 314                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 315                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 316                },
 317                .name                   = "focaltech_etm070003dh6",
 318        },
 319
 320        /* Microtips Technologies - UMSH-8173MD */
 321        {
 322                {
 323                        .x_res          = 800,
 324                        .y_res          = 480,
 325
 326                        .pixel_clock    = 34560,
 327
 328                        .hsw            = 13,
 329                        .hfp            = 101,
 330                        .hbp            = 101,
 331
 332                        .vsw            = 23,
 333                        .vfp            = 1,
 334                        .vbp            = 1,
 335
 336                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 337                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 338                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 339                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 340                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 341                },
 342                .power_on_delay         = 0,
 343                .power_off_delay        = 0,
 344                .name                   = "microtips_umsh_8173md",
 345        },
 346
 347        /* OrtusTech COM43H4M10XTC */
 348        {
 349                {
 350                        .x_res          = 480,
 351                        .y_res          = 272,
 352
 353                        .pixel_clock    = 8000,
 354
 355                        .hsw            = 41,
 356                        .hfp            = 8,
 357                        .hbp            = 4,
 358
 359                        .vsw            = 10,
 360                        .vfp            = 4,
 361                        .vbp            = 2,
 362
 363                        .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 364                        .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 365                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 366                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 367                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 368                },
 369                .name                   = "ortustech_com43h4m10xtc",
 370        },
 371
 372        /* Innolux AT080TN52 */
 373        {
 374                {
 375                        .x_res = 800,
 376                        .y_res = 600,
 377
 378                        .pixel_clock    = 41142,
 379
 380                        .hsw            = 20,
 381                        .hfp            = 210,
 382                        .hbp            = 46,
 383
 384                        .vsw            = 10,
 385                        .vfp            = 12,
 386                        .vbp            = 23,
 387
 388                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 389                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 390                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 391                        .de_level       = OMAPDSS_SIG_ACTIVE_LOW,
 392                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 393                },
 394                .name                   = "innolux_at080tn52",
 395        },
 396
 397        /* Mitsubishi AA084SB01 */
 398        {
 399                {
 400                        .x_res          = 800,
 401                        .y_res          = 600,
 402                        .pixel_clock    = 40000,
 403
 404                        .hsw            = 1,
 405                        .hfp            = 254,
 406                        .hbp            = 1,
 407
 408                        .vsw            = 1,
 409                        .vfp            = 26,
 410                        .vbp            = 1,
 411
 412                        .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 413                        .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 414                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 415                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 416                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 417                },
 418                .name                   = "mitsubishi_aa084sb01",
 419        },
 420        /* EDT ET0500G0DH6 */
 421        {
 422                {
 423                        .x_res          = 800,
 424                        .y_res          = 480,
 425                        .pixel_clock    = 33260,
 426
 427                        .hsw            = 128,
 428                        .hfp            = 216,
 429                        .hbp            = 40,
 430
 431                        .vsw            = 2,
 432                        .vfp            = 35,
 433                        .vbp            = 10,
 434
 435                        .vsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 436                        .hsync_level    = OMAPDSS_SIG_ACTIVE_HIGH,
 437                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
 438                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 439                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 440                },
 441                .name                   = "edt_et0500g0dh6",
 442        },
 443
 444        /* Prime-View PD050VL1 */
 445        {
 446                {
 447                        .x_res          = 640,
 448                        .y_res          = 480,
 449
 450                        .pixel_clock    = 25000,
 451
 452                        .hsw            = 96,
 453                        .hfp            = 18,
 454                        .hbp            = 46,
 455
 456                        .vsw            = 2,
 457                        .vfp            = 10,
 458                        .vbp            = 33,
 459
 460                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 461                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 462                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 463                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 464                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 465                },
 466                .name                   = "primeview_pd050vl1",
 467        },
 468
 469        /* Prime-View PM070WL4 */
 470        {
 471                {
 472                        .x_res          = 800,
 473                        .y_res          = 480,
 474
 475                        .pixel_clock    = 32000,
 476
 477                        .hsw            = 128,
 478                        .hfp            = 42,
 479                        .hbp            = 86,
 480
 481                        .vsw            = 2,
 482                        .vfp            = 10,
 483                        .vbp            = 33,
 484
 485                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 486                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 487                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 488                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 489                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 490                },
 491                .name                   = "primeview_pm070wl4",
 492        },
 493
 494        /* Prime-View PD104SLF */
 495        {
 496                {
 497                        .x_res          = 800,
 498                        .y_res          = 600,
 499
 500                        .pixel_clock    = 40000,
 501
 502                        .hsw            = 128,
 503                        .hfp            = 42,
 504                        .hbp            = 86,
 505
 506                        .vsw            = 4,
 507                        .vfp            = 1,
 508                        .vbp            = 23,
 509
 510                        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 511                        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
 512                        .data_pclk_edge = OMAPDSS_DRIVE_SIG_FALLING_EDGE,
 513                        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
 514                        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_OPPOSITE_EDGES,
 515                },
 516                .name                   = "primeview_pd104slf",
 517        },
 518};
 519
 520struct panel_drv_data {
 521
 522        struct omap_dss_device *dssdev;
 523
 524        struct panel_config *panel_config;
 525
 526        struct mutex lock;
 527};
 528
 529static inline struct panel_generic_dpi_data
 530*get_panel_data(const struct omap_dss_device *dssdev)
 531{
 532        return (struct panel_generic_dpi_data *) dssdev->data;
 533}
 534
 535static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
 536{
 537        int r, i;
 538        struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
 539        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 540        struct panel_config *panel_config = drv_data->panel_config;
 541
 542        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 543                return 0;
 544
 545        omapdss_dpi_set_timings(dssdev, &dssdev->panel.timings);
 546        omapdss_dpi_set_data_lines(dssdev, dssdev->phy.dpi.data_lines);
 547
 548        r = omapdss_dpi_display_enable(dssdev);
 549        if (r)
 550                goto err0;
 551
 552        /* wait couple of vsyncs until enabling the LCD */
 553        if (panel_config->power_on_delay)
 554                msleep(panel_config->power_on_delay);
 555
 556        for (i = 0; i < panel_data->num_gpios; ++i) {
 557                gpio_set_value_cansleep(panel_data->gpios[i],
 558                                panel_data->gpio_invert[i] ? 0 : 1);
 559        }
 560
 561        return 0;
 562
 563err0:
 564        return r;
 565}
 566
 567static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
 568{
 569        struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
 570        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 571        struct panel_config *panel_config = drv_data->panel_config;
 572        int i;
 573
 574        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 575                return;
 576
 577        for (i = panel_data->num_gpios - 1; i >= 0; --i) {
 578                gpio_set_value_cansleep(panel_data->gpios[i],
 579                                panel_data->gpio_invert[i] ? 1 : 0);
 580        }
 581
 582        /* wait couple of vsyncs after disabling the LCD */
 583        if (panel_config->power_off_delay)
 584                msleep(panel_config->power_off_delay);
 585
 586        omapdss_dpi_display_disable(dssdev);
 587}
 588
 589static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
 590{
 591        struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
 592        struct panel_config *panel_config = NULL;
 593        struct panel_drv_data *drv_data = NULL;
 594        int i, r;
 595
 596        dev_dbg(&dssdev->dev, "probe\n");
 597
 598        if (!panel_data || !panel_data->name)
 599                return -EINVAL;
 600
 601        for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
 602                if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
 603                        panel_config = &generic_dpi_panels[i];
 604                        break;
 605                }
 606        }
 607
 608        if (!panel_config)
 609                return -EINVAL;
 610
 611        for (i = 0; i < panel_data->num_gpios; ++i) {
 612                r = devm_gpio_request_one(&dssdev->dev, panel_data->gpios[i],
 613                                panel_data->gpio_invert[i] ?
 614                                GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW,
 615                                "panel gpio");
 616                if (r)
 617                        return r;
 618        }
 619
 620        dssdev->panel.timings = panel_config->timings;
 621
 622        drv_data = devm_kzalloc(&dssdev->dev, sizeof(*drv_data), GFP_KERNEL);
 623        if (!drv_data)
 624                return -ENOMEM;
 625
 626        drv_data->dssdev = dssdev;
 627        drv_data->panel_config = panel_config;
 628
 629        mutex_init(&drv_data->lock);
 630
 631        dev_set_drvdata(&dssdev->dev, drv_data);
 632
 633        return 0;
 634}
 635
 636static void __exit generic_dpi_panel_remove(struct omap_dss_device *dssdev)
 637{
 638        dev_dbg(&dssdev->dev, "remove\n");
 639
 640        dev_set_drvdata(&dssdev->dev, NULL);
 641}
 642
 643static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
 644{
 645        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 646        int r;
 647
 648        mutex_lock(&drv_data->lock);
 649
 650        r = generic_dpi_panel_power_on(dssdev);
 651        if (r)
 652                goto err;
 653
 654        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 655err:
 656        mutex_unlock(&drv_data->lock);
 657
 658        return r;
 659}
 660
 661static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
 662{
 663        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 664
 665        mutex_lock(&drv_data->lock);
 666
 667        generic_dpi_panel_power_off(dssdev);
 668
 669        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 670
 671        mutex_unlock(&drv_data->lock);
 672}
 673
 674static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
 675                struct omap_video_timings *timings)
 676{
 677        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 678
 679        mutex_lock(&drv_data->lock);
 680
 681        omapdss_dpi_set_timings(dssdev, timings);
 682
 683        dssdev->panel.timings = *timings;
 684
 685        mutex_unlock(&drv_data->lock);
 686}
 687
 688static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
 689                struct omap_video_timings *timings)
 690{
 691        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 692
 693        mutex_lock(&drv_data->lock);
 694
 695        *timings = dssdev->panel.timings;
 696
 697        mutex_unlock(&drv_data->lock);
 698}
 699
 700static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
 701                struct omap_video_timings *timings)
 702{
 703        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 704        int r;
 705
 706        mutex_lock(&drv_data->lock);
 707
 708        r = dpi_check_timings(dssdev, timings);
 709
 710        mutex_unlock(&drv_data->lock);
 711
 712        return r;
 713}
 714
 715static struct omap_dss_driver dpi_driver = {
 716        .probe          = generic_dpi_panel_probe,
 717        .remove         = __exit_p(generic_dpi_panel_remove),
 718
 719        .enable         = generic_dpi_panel_enable,
 720        .disable        = generic_dpi_panel_disable,
 721
 722        .set_timings    = generic_dpi_panel_set_timings,
 723        .get_timings    = generic_dpi_panel_get_timings,
 724        .check_timings  = generic_dpi_panel_check_timings,
 725
 726        .driver         = {
 727                .name   = "generic_dpi_panel",
 728                .owner  = THIS_MODULE,
 729        },
 730};
 731
 732static int __init generic_dpi_panel_drv_init(void)
 733{
 734        return omap_dss_register_driver(&dpi_driver);
 735}
 736
 737static void __exit generic_dpi_panel_drv_exit(void)
 738{
 739        omap_dss_unregister_driver(&dpi_driver);
 740}
 741
 742module_init(generic_dpi_panel_drv_init);
 743module_exit(generic_dpi_panel_drv_exit);
 744MODULE_LICENSE("GPL");
 745