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
  37#include <plat/panel-generic-dpi.h>
  38
  39struct panel_config {
  40        struct omap_video_timings timings;
  41
  42        int acbi;       /* ac-bias pin transitions per interrupt */
  43        /* Unit: line clocks */
  44        int acb;        /* ac-bias pin frequency */
  45
  46        enum omap_panel_config config;
  47
  48        int power_on_delay;
  49        int power_off_delay;
  50
  51        /*
  52         * Used to match device to panel configuration
  53         * when use generic panel driver
  54         */
  55        const char *name;
  56};
  57
  58/* Panel configurations */
  59static struct panel_config generic_dpi_panels[] = {
  60        /* Generic Panel */
  61        {
  62                {
  63                        .x_res          = 640,
  64                        .y_res          = 480,
  65
  66                        .pixel_clock    = 23500,
  67
  68                        .hfp            = 48,
  69                        .hsw            = 32,
  70                        .hbp            = 80,
  71
  72                        .vfp            = 3,
  73                        .vsw            = 4,
  74                        .vbp            = 7,
  75                },
  76                .acbi                   = 0x0,
  77                .acb                    = 0x0,
  78                .config                 = OMAP_DSS_LCD_TFT,
  79                .power_on_delay         = 0,
  80                .power_off_delay        = 0,
  81                .name                   = "generic",
  82        },
  83
  84        /* Sharp LQ043T1DG01 */
  85        {
  86                {
  87                        .x_res          = 480,
  88                        .y_res          = 272,
  89
  90                        .pixel_clock    = 9000,
  91
  92                        .hsw            = 42,
  93                        .hfp            = 3,
  94                        .hbp            = 2,
  95
  96                        .vsw            = 11,
  97                        .vfp            = 3,
  98                        .vbp            = 2,
  99                },
 100                .acbi                   = 0x0,
 101                .acb                    = 0x0,
 102                .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
 103                                        OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IEO,
 104                .power_on_delay         = 50,
 105                .power_off_delay        = 100,
 106                .name                   = "sharp_lq",
 107        },
 108
 109        /* Sharp LS037V7DW01 */
 110        {
 111                {
 112                        .x_res          = 480,
 113                        .y_res          = 640,
 114
 115                        .pixel_clock    = 19200,
 116
 117                        .hsw            = 2,
 118                        .hfp            = 1,
 119                        .hbp            = 28,
 120
 121                        .vsw            = 1,
 122                        .vfp            = 1,
 123                        .vbp            = 1,
 124                },
 125                .acbi                   = 0x0,
 126                .acb                    = 0x28,
 127                .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
 128                                                OMAP_DSS_LCD_IHS,
 129                .power_on_delay         = 50,
 130                .power_off_delay        = 100,
 131                .name                   = "sharp_ls",
 132        },
 133
 134        /* Toppoly TDO35S */
 135        {
 136                {
 137                        .x_res          = 480,
 138                        .y_res          = 640,
 139
 140                        .pixel_clock    = 26000,
 141
 142                        .hfp            = 104,
 143                        .hsw            = 8,
 144                        .hbp            = 8,
 145
 146                        .vfp            = 4,
 147                        .vsw            = 2,
 148                        .vbp            = 2,
 149                },
 150                .acbi                   = 0x0,
 151                .acb                    = 0x0,
 152                .config                 = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
 153                                        OMAP_DSS_LCD_IHS | OMAP_DSS_LCD_IPC |
 154                                        OMAP_DSS_LCD_ONOFF,
 155                .power_on_delay         = 0,
 156                .power_off_delay        = 0,
 157                .name                   = "toppoly_tdo35s",
 158        },
 159};
 160
 161struct panel_drv_data {
 162
 163        struct omap_dss_device *dssdev;
 164
 165        struct panel_config *panel_config;
 166};
 167
 168static inline struct panel_generic_dpi_data
 169*get_panel_data(const struct omap_dss_device *dssdev)
 170{
 171        return (struct panel_generic_dpi_data *) dssdev->data;
 172}
 173
 174static int generic_dpi_panel_power_on(struct omap_dss_device *dssdev)
 175{
 176        int r;
 177        struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
 178        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 179        struct panel_config *panel_config = drv_data->panel_config;
 180
 181        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 182                return 0;
 183
 184        r = omapdss_dpi_display_enable(dssdev);
 185        if (r)
 186                goto err0;
 187
 188        /* wait couple of vsyncs until enabling the LCD */
 189        if (panel_config->power_on_delay)
 190                msleep(panel_config->power_on_delay);
 191
 192        if (panel_data->platform_enable) {
 193                r = panel_data->platform_enable(dssdev);
 194                if (r)
 195                        goto err1;
 196        }
 197
 198        return 0;
 199err1:
 200        omapdss_dpi_display_disable(dssdev);
 201err0:
 202        return r;
 203}
 204
 205static void generic_dpi_panel_power_off(struct omap_dss_device *dssdev)
 206{
 207        struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
 208        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 209        struct panel_config *panel_config = drv_data->panel_config;
 210
 211        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 212                return;
 213
 214        if (panel_data->platform_disable)
 215                panel_data->platform_disable(dssdev);
 216
 217        /* wait couple of vsyncs after disabling the LCD */
 218        if (panel_config->power_off_delay)
 219                msleep(panel_config->power_off_delay);
 220
 221        omapdss_dpi_display_disable(dssdev);
 222}
 223
 224static int generic_dpi_panel_probe(struct omap_dss_device *dssdev)
 225{
 226        struct panel_generic_dpi_data *panel_data = get_panel_data(dssdev);
 227        struct panel_config *panel_config = NULL;
 228        struct panel_drv_data *drv_data = NULL;
 229        int i;
 230
 231        dev_dbg(&dssdev->dev, "probe\n");
 232
 233        if (!panel_data || !panel_data->name)
 234                return -EINVAL;
 235
 236        for (i = 0; i < ARRAY_SIZE(generic_dpi_panels); i++) {
 237                if (strcmp(panel_data->name, generic_dpi_panels[i].name) == 0) {
 238                        panel_config = &generic_dpi_panels[i];
 239                        break;
 240                }
 241        }
 242
 243        if (!panel_config)
 244                return -EINVAL;
 245
 246        dssdev->panel.config = panel_config->config;
 247        dssdev->panel.timings = panel_config->timings;
 248        dssdev->panel.acb = panel_config->acb;
 249        dssdev->panel.acbi = panel_config->acbi;
 250
 251        drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
 252        if (!drv_data)
 253                return -ENOMEM;
 254
 255        drv_data->dssdev = dssdev;
 256        drv_data->panel_config = panel_config;
 257
 258        dev_set_drvdata(&dssdev->dev, drv_data);
 259
 260        return 0;
 261}
 262
 263static void generic_dpi_panel_remove(struct omap_dss_device *dssdev)
 264{
 265        struct panel_drv_data *drv_data = dev_get_drvdata(&dssdev->dev);
 266
 267        dev_dbg(&dssdev->dev, "remove\n");
 268
 269        kfree(drv_data);
 270
 271        dev_set_drvdata(&dssdev->dev, NULL);
 272}
 273
 274static int generic_dpi_panel_enable(struct omap_dss_device *dssdev)
 275{
 276        int r = 0;
 277
 278        r = generic_dpi_panel_power_on(dssdev);
 279        if (r)
 280                return r;
 281
 282        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 283
 284        return 0;
 285}
 286
 287static void generic_dpi_panel_disable(struct omap_dss_device *dssdev)
 288{
 289        generic_dpi_panel_power_off(dssdev);
 290
 291        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 292}
 293
 294static int generic_dpi_panel_suspend(struct omap_dss_device *dssdev)
 295{
 296        generic_dpi_panel_power_off(dssdev);
 297
 298        dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 299
 300        return 0;
 301}
 302
 303static int generic_dpi_panel_resume(struct omap_dss_device *dssdev)
 304{
 305        int r = 0;
 306
 307        r = generic_dpi_panel_power_on(dssdev);
 308        if (r)
 309                return r;
 310
 311        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 312
 313        return 0;
 314}
 315
 316static void generic_dpi_panel_set_timings(struct omap_dss_device *dssdev,
 317                struct omap_video_timings *timings)
 318{
 319        dpi_set_timings(dssdev, timings);
 320}
 321
 322static void generic_dpi_panel_get_timings(struct omap_dss_device *dssdev,
 323                struct omap_video_timings *timings)
 324{
 325        *timings = dssdev->panel.timings;
 326}
 327
 328static int generic_dpi_panel_check_timings(struct omap_dss_device *dssdev,
 329                struct omap_video_timings *timings)
 330{
 331        return dpi_check_timings(dssdev, timings);
 332}
 333
 334static struct omap_dss_driver dpi_driver = {
 335        .probe          = generic_dpi_panel_probe,
 336        .remove         = generic_dpi_panel_remove,
 337
 338        .enable         = generic_dpi_panel_enable,
 339        .disable        = generic_dpi_panel_disable,
 340        .suspend        = generic_dpi_panel_suspend,
 341        .resume         = generic_dpi_panel_resume,
 342
 343        .set_timings    = generic_dpi_panel_set_timings,
 344        .get_timings    = generic_dpi_panel_get_timings,
 345        .check_timings  = generic_dpi_panel_check_timings,
 346
 347        .driver         = {
 348                .name   = "generic_dpi_panel",
 349                .owner  = THIS_MODULE,
 350        },
 351};
 352
 353static int __init generic_dpi_panel_drv_init(void)
 354{
 355        return omap_dss_register_driver(&dpi_driver);
 356}
 357
 358static void __exit generic_dpi_panel_drv_exit(void)
 359{
 360        omap_dss_unregister_driver(&dpi_driver);
 361}
 362
 363module_init(generic_dpi_panel_drv_init);
 364module_exit(generic_dpi_panel_drv_exit);
 365MODULE_LICENSE("GPL");
 366