linux/drivers/video/fbdev/omap2/omapfb/displays/panel-nec-nl8048hl11.c
<<
>>
Prefs
   1/*
   2 * NEC NL8048HL11 Panel driver
   3 *
   4 * Copyright (C) 2010 Texas Instruments Inc.
   5 * Author: Erik Gilling <konkers@android.com>
   6 * Converted to new DSS device model: Tomi Valkeinen <tomi.valkeinen@ti.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 */
  13
  14#include <linux/module.h>
  15#include <linux/delay.h>
  16#include <linux/spi/spi.h>
  17#include <linux/fb.h>
  18#include <linux/gpio.h>
  19#include <linux/of_gpio.h>
  20
  21#include <video/omapdss.h>
  22#include <video/omap-panel-data.h>
  23
  24struct panel_drv_data {
  25        struct omap_dss_device  dssdev;
  26        struct omap_dss_device *in;
  27
  28        struct omap_video_timings videomode;
  29
  30        int data_lines;
  31
  32        int res_gpio;
  33        int qvga_gpio;
  34
  35        struct spi_device *spi;
  36};
  37
  38#define LCD_XRES                800
  39#define LCD_YRES                480
  40/*
  41 * NEC PIX Clock Ratings
  42 * MIN:21.8MHz TYP:23.8MHz MAX:25.7MHz
  43 */
  44#define LCD_PIXEL_CLOCK         23800000
  45
  46static const struct {
  47        unsigned char addr;
  48        unsigned char dat;
  49} nec_8048_init_seq[] = {
  50        { 3, 0x01 }, { 0, 0x00 }, { 1, 0x01 }, { 4, 0x00 }, { 5, 0x14 },
  51        { 6, 0x24 }, { 16, 0xD7 }, { 17, 0x00 }, { 18, 0x00 }, { 19, 0x55 },
  52        { 20, 0x01 }, { 21, 0x70 }, { 22, 0x1E }, { 23, 0x25 }, { 24, 0x25 },
  53        { 25, 0x02 }, { 26, 0x02 }, { 27, 0xA0 }, { 32, 0x2F }, { 33, 0x0F },
  54        { 34, 0x0F }, { 35, 0x0F }, { 36, 0x0F }, { 37, 0x0F }, { 38, 0x0F },
  55        { 39, 0x00 }, { 40, 0x02 }, { 41, 0x02 }, { 42, 0x02 }, { 43, 0x0F },
  56        { 44, 0x0F }, { 45, 0x0F }, { 46, 0x0F }, { 47, 0x0F }, { 48, 0x0F },
  57        { 49, 0x0F }, { 50, 0x00 }, { 51, 0x02 }, { 52, 0x02 }, { 53, 0x02 },
  58        { 80, 0x0C }, { 83, 0x42 }, { 84, 0x42 }, { 85, 0x41 }, { 86, 0x14 },
  59        { 89, 0x88 }, { 90, 0x01 }, { 91, 0x00 }, { 92, 0x02 }, { 93, 0x0C },
  60        { 94, 0x1C }, { 95, 0x27 }, { 98, 0x49 }, { 99, 0x27 }, { 102, 0x76 },
  61        { 103, 0x27 }, { 112, 0x01 }, { 113, 0x0E }, { 114, 0x02 },
  62        { 115, 0x0C }, { 118, 0x0C }, { 121, 0x30 }, { 130, 0x00 },
  63        { 131, 0x00 }, { 132, 0xFC }, { 134, 0x00 }, { 136, 0x00 },
  64        { 138, 0x00 }, { 139, 0x00 }, { 140, 0x00 }, { 141, 0xFC },
  65        { 143, 0x00 }, { 145, 0x00 }, { 147, 0x00 }, { 148, 0x00 },
  66        { 149, 0x00 }, { 150, 0xFC }, { 152, 0x00 }, { 154, 0x00 },
  67        { 156, 0x00 }, { 157, 0x00 }, { 2, 0x00 },
  68};
  69
  70static const struct omap_video_timings nec_8048_panel_timings = {
  71        .x_res          = LCD_XRES,
  72        .y_res          = LCD_YRES,
  73        .pixelclock     = LCD_PIXEL_CLOCK,
  74        .hfp            = 6,
  75        .hsw            = 1,
  76        .hbp            = 4,
  77        .vfp            = 3,
  78        .vsw            = 1,
  79        .vbp            = 4,
  80
  81        .vsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  82        .hsync_level    = OMAPDSS_SIG_ACTIVE_LOW,
  83        .data_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
  84        .de_level       = OMAPDSS_SIG_ACTIVE_HIGH,
  85        .sync_pclk_edge = OMAPDSS_DRIVE_SIG_RISING_EDGE,
  86};
  87
  88#define to_panel_data(p) container_of(p, struct panel_drv_data, dssdev)
  89
  90static int nec_8048_spi_send(struct spi_device *spi, unsigned char reg_addr,
  91                        unsigned char reg_data)
  92{
  93        int ret = 0;
  94        unsigned int cmd = 0, data = 0;
  95
  96        cmd = 0x0000 | reg_addr; /* register address write */
  97        data = 0x0100 | reg_data; /* register data write */
  98        data = (cmd << 16) | data;
  99
 100        ret = spi_write(spi, (unsigned char *)&data, 4);
 101        if (ret)
 102                pr_err("error in spi_write %x\n", data);
 103
 104        return ret;
 105}
 106
 107static int init_nec_8048_wvga_lcd(struct spi_device *spi)
 108{
 109        unsigned int i;
 110        /* Initialization Sequence */
 111        /* nec_8048_spi_send(spi, REG, VAL) */
 112        for (i = 0; i < (ARRAY_SIZE(nec_8048_init_seq) - 1); i++)
 113                nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
 114                                nec_8048_init_seq[i].dat);
 115        udelay(20);
 116        nec_8048_spi_send(spi, nec_8048_init_seq[i].addr,
 117                                nec_8048_init_seq[i].dat);
 118        return 0;
 119}
 120
 121static int nec_8048_connect(struct omap_dss_device *dssdev)
 122{
 123        struct panel_drv_data *ddata = to_panel_data(dssdev);
 124        struct omap_dss_device *in = ddata->in;
 125        int r;
 126
 127        if (omapdss_device_is_connected(dssdev))
 128                return 0;
 129
 130        r = in->ops.dpi->connect(in, dssdev);
 131        if (r)
 132                return r;
 133
 134        return 0;
 135}
 136
 137static void nec_8048_disconnect(struct omap_dss_device *dssdev)
 138{
 139        struct panel_drv_data *ddata = to_panel_data(dssdev);
 140        struct omap_dss_device *in = ddata->in;
 141
 142        if (!omapdss_device_is_connected(dssdev))
 143                return;
 144
 145        in->ops.dpi->disconnect(in, dssdev);
 146}
 147
 148static int nec_8048_enable(struct omap_dss_device *dssdev)
 149{
 150        struct panel_drv_data *ddata = to_panel_data(dssdev);
 151        struct omap_dss_device *in = ddata->in;
 152        int r;
 153
 154        if (!omapdss_device_is_connected(dssdev))
 155                return -ENODEV;
 156
 157        if (omapdss_device_is_enabled(dssdev))
 158                return 0;
 159
 160        if (ddata->data_lines)
 161                in->ops.dpi->set_data_lines(in, ddata->data_lines);
 162        in->ops.dpi->set_timings(in, &ddata->videomode);
 163
 164        r = in->ops.dpi->enable(in);
 165        if (r)
 166                return r;
 167
 168        if (gpio_is_valid(ddata->res_gpio))
 169                gpio_set_value_cansleep(ddata->res_gpio, 1);
 170
 171        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 172
 173        return 0;
 174}
 175
 176static void nec_8048_disable(struct omap_dss_device *dssdev)
 177{
 178        struct panel_drv_data *ddata = to_panel_data(dssdev);
 179        struct omap_dss_device *in = ddata->in;
 180
 181        if (!omapdss_device_is_enabled(dssdev))
 182                return;
 183
 184        if (gpio_is_valid(ddata->res_gpio))
 185                gpio_set_value_cansleep(ddata->res_gpio, 0);
 186
 187        in->ops.dpi->disable(in);
 188
 189        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 190}
 191
 192static void nec_8048_set_timings(struct omap_dss_device *dssdev,
 193                struct omap_video_timings *timings)
 194{
 195        struct panel_drv_data *ddata = to_panel_data(dssdev);
 196        struct omap_dss_device *in = ddata->in;
 197
 198        ddata->videomode = *timings;
 199        dssdev->panel.timings = *timings;
 200
 201        in->ops.dpi->set_timings(in, timings);
 202}
 203
 204static void nec_8048_get_timings(struct omap_dss_device *dssdev,
 205                struct omap_video_timings *timings)
 206{
 207        struct panel_drv_data *ddata = to_panel_data(dssdev);
 208
 209        *timings = ddata->videomode;
 210}
 211
 212static int nec_8048_check_timings(struct omap_dss_device *dssdev,
 213                struct omap_video_timings *timings)
 214{
 215        struct panel_drv_data *ddata = to_panel_data(dssdev);
 216        struct omap_dss_device *in = ddata->in;
 217
 218        return in->ops.dpi->check_timings(in, timings);
 219}
 220
 221static struct omap_dss_driver nec_8048_ops = {
 222        .connect        = nec_8048_connect,
 223        .disconnect     = nec_8048_disconnect,
 224
 225        .enable         = nec_8048_enable,
 226        .disable        = nec_8048_disable,
 227
 228        .set_timings    = nec_8048_set_timings,
 229        .get_timings    = nec_8048_get_timings,
 230        .check_timings  = nec_8048_check_timings,
 231
 232        .get_resolution = omapdss_default_get_resolution,
 233};
 234
 235
 236static int nec_8048_probe_pdata(struct spi_device *spi)
 237{
 238        const struct panel_nec_nl8048hl11_platform_data *pdata;
 239        struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 240        struct omap_dss_device *dssdev, *in;
 241
 242        pdata = dev_get_platdata(&spi->dev);
 243
 244        ddata->qvga_gpio = pdata->qvga_gpio;
 245        ddata->res_gpio = pdata->res_gpio;
 246
 247        in = omap_dss_find_output(pdata->source);
 248        if (in == NULL) {
 249                dev_err(&spi->dev, "failed to find video source '%s'\n",
 250                                pdata->source);
 251                return -EPROBE_DEFER;
 252        }
 253        ddata->in = in;
 254
 255        ddata->data_lines = pdata->data_lines;
 256
 257        dssdev = &ddata->dssdev;
 258        dssdev->name = pdata->name;
 259
 260        return 0;
 261}
 262
 263static int nec_8048_probe_of(struct spi_device *spi)
 264{
 265        struct device_node *node = spi->dev.of_node;
 266        struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 267        struct omap_dss_device *in;
 268        int gpio;
 269
 270        gpio = of_get_named_gpio(node, "reset-gpios", 0);
 271        if (!gpio_is_valid(gpio)) {
 272                dev_err(&spi->dev, "failed to parse enable gpio\n");
 273                return gpio;
 274        }
 275        ddata->res_gpio = gpio;
 276
 277        /* XXX the panel spec doesn't mention any QVGA pin?? */
 278        ddata->qvga_gpio = -ENOENT;
 279
 280        in = omapdss_of_find_source_for_first_ep(node);
 281        if (IS_ERR(in)) {
 282                dev_err(&spi->dev, "failed to find video source\n");
 283                return PTR_ERR(in);
 284        }
 285
 286        ddata->in = in;
 287
 288        return 0;
 289}
 290
 291static int nec_8048_probe(struct spi_device *spi)
 292{
 293        struct panel_drv_data *ddata;
 294        struct omap_dss_device *dssdev;
 295        int r;
 296
 297        dev_dbg(&spi->dev, "%s\n", __func__);
 298
 299        spi->mode = SPI_MODE_0;
 300        spi->bits_per_word = 32;
 301
 302        r = spi_setup(spi);
 303        if (r < 0) {
 304                dev_err(&spi->dev, "spi_setup failed: %d\n", r);
 305                return r;
 306        }
 307
 308        init_nec_8048_wvga_lcd(spi);
 309
 310        ddata = devm_kzalloc(&spi->dev, sizeof(*ddata), GFP_KERNEL);
 311        if (ddata == NULL)
 312                return -ENOMEM;
 313
 314        dev_set_drvdata(&spi->dev, ddata);
 315
 316        ddata->spi = spi;
 317
 318        if (dev_get_platdata(&spi->dev)) {
 319                r = nec_8048_probe_pdata(spi);
 320                if (r)
 321                        return r;
 322        } else if (spi->dev.of_node) {
 323                r = nec_8048_probe_of(spi);
 324                if (r)
 325                        return r;
 326        } else {
 327                return -ENODEV;
 328        }
 329
 330        if (gpio_is_valid(ddata->qvga_gpio)) {
 331                r = devm_gpio_request_one(&spi->dev, ddata->qvga_gpio,
 332                                GPIOF_OUT_INIT_HIGH, "lcd QVGA");
 333                if (r)
 334                        goto err_gpio;
 335        }
 336
 337        if (gpio_is_valid(ddata->res_gpio)) {
 338                r = devm_gpio_request_one(&spi->dev, ddata->res_gpio,
 339                                GPIOF_OUT_INIT_LOW, "lcd RES");
 340                if (r)
 341                        goto err_gpio;
 342        }
 343
 344        ddata->videomode = nec_8048_panel_timings;
 345
 346        dssdev = &ddata->dssdev;
 347        dssdev->dev = &spi->dev;
 348        dssdev->driver = &nec_8048_ops;
 349        dssdev->type = OMAP_DISPLAY_TYPE_DPI;
 350        dssdev->owner = THIS_MODULE;
 351        dssdev->panel.timings = ddata->videomode;
 352
 353        r = omapdss_register_display(dssdev);
 354        if (r) {
 355                dev_err(&spi->dev, "Failed to register panel\n");
 356                goto err_reg;
 357        }
 358
 359        return 0;
 360
 361err_reg:
 362err_gpio:
 363        omap_dss_put_device(ddata->in);
 364        return r;
 365}
 366
 367static int nec_8048_remove(struct spi_device *spi)
 368{
 369        struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
 370        struct omap_dss_device *dssdev = &ddata->dssdev;
 371        struct omap_dss_device *in = ddata->in;
 372
 373        dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 374
 375        omapdss_unregister_display(dssdev);
 376
 377        nec_8048_disable(dssdev);
 378        nec_8048_disconnect(dssdev);
 379
 380        omap_dss_put_device(in);
 381
 382        return 0;
 383}
 384
 385#ifdef CONFIG_PM_SLEEP
 386static int nec_8048_suspend(struct device *dev)
 387{
 388        struct spi_device *spi = to_spi_device(dev);
 389
 390        nec_8048_spi_send(spi, 2, 0x01);
 391        mdelay(40);
 392
 393        return 0;
 394}
 395
 396static int nec_8048_resume(struct device *dev)
 397{
 398        struct spi_device *spi = to_spi_device(dev);
 399
 400        /* reinitialize the panel */
 401        spi_setup(spi);
 402        nec_8048_spi_send(spi, 2, 0x00);
 403        init_nec_8048_wvga_lcd(spi);
 404
 405        return 0;
 406}
 407static SIMPLE_DEV_PM_OPS(nec_8048_pm_ops, nec_8048_suspend,
 408                nec_8048_resume);
 409#define NEC_8048_PM_OPS (&nec_8048_pm_ops)
 410#else
 411#define NEC_8048_PM_OPS NULL
 412#endif
 413
 414static const struct of_device_id nec_8048_of_match[] = {
 415        { .compatible = "omapdss,nec,nl8048hl11", },
 416        {},
 417};
 418
 419MODULE_DEVICE_TABLE(of, nec_8048_of_match);
 420
 421static struct spi_driver nec_8048_driver = {
 422        .driver = {
 423                .name   = "panel-nec-nl8048hl11",
 424                .pm     = NEC_8048_PM_OPS,
 425                .of_match_table = nec_8048_of_match,
 426                .suppress_bind_attrs = true,
 427        },
 428        .probe  = nec_8048_probe,
 429        .remove = nec_8048_remove,
 430};
 431
 432module_spi_driver(nec_8048_driver);
 433
 434MODULE_ALIAS("spi:nec,nl8048hl11");
 435MODULE_AUTHOR("Erik Gilling <konkers@android.com>");
 436MODULE_DESCRIPTION("NEC-NL8048HL11 Driver");
 437MODULE_LICENSE("GPL");
 438