linux/drivers/video/omap2/displays/panel-n8x0.c
<<
>>
Prefs
   1/* #define DEBUG */
   2
   3#include <linux/module.h>
   4#include <linux/delay.h>
   5#include <linux/slab.h>
   6#include <linux/gpio.h>
   7#include <linux/spi/spi.h>
   8#include <linux/backlight.h>
   9#include <linux/fb.h>
  10
  11#include <video/omapdss.h>
  12#include <video/omap-panel-n8x0.h>
  13
  14#define BLIZZARD_REV_CODE                      0x00
  15#define BLIZZARD_CONFIG                        0x02
  16#define BLIZZARD_PLL_DIV                       0x04
  17#define BLIZZARD_PLL_LOCK_RANGE                0x06
  18#define BLIZZARD_PLL_CLOCK_SYNTH_0             0x08
  19#define BLIZZARD_PLL_CLOCK_SYNTH_1             0x0a
  20#define BLIZZARD_PLL_MODE                      0x0c
  21#define BLIZZARD_CLK_SRC                       0x0e
  22#define BLIZZARD_MEM_BANK0_ACTIVATE            0x10
  23#define BLIZZARD_MEM_BANK0_STATUS              0x14
  24#define BLIZZARD_PANEL_CONFIGURATION           0x28
  25#define BLIZZARD_HDISP                         0x2a
  26#define BLIZZARD_HNDP                          0x2c
  27#define BLIZZARD_VDISP0                        0x2e
  28#define BLIZZARD_VDISP1                        0x30
  29#define BLIZZARD_VNDP                          0x32
  30#define BLIZZARD_HSW                           0x34
  31#define BLIZZARD_VSW                           0x38
  32#define BLIZZARD_DISPLAY_MODE                  0x68
  33#define BLIZZARD_INPUT_WIN_X_START_0           0x6c
  34#define BLIZZARD_DATA_SOURCE_SELECT            0x8e
  35#define BLIZZARD_DISP_MEM_DATA_PORT            0x90
  36#define BLIZZARD_DISP_MEM_READ_ADDR0           0x92
  37#define BLIZZARD_POWER_SAVE                    0xE6
  38#define BLIZZARD_NDISP_CTRL_STATUS             0xE8
  39
  40/* Data source select */
  41/* For S1D13745 */
  42#define BLIZZARD_SRC_WRITE_LCD_BACKGROUND       0x00
  43#define BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE      0x01
  44#define BLIZZARD_SRC_WRITE_OVERLAY_ENABLE       0x04
  45#define BLIZZARD_SRC_DISABLE_OVERLAY            0x05
  46/* For S1D13744 */
  47#define BLIZZARD_SRC_WRITE_LCD                  0x00
  48#define BLIZZARD_SRC_BLT_LCD                    0x06
  49
  50#define BLIZZARD_COLOR_RGB565                   0x01
  51#define BLIZZARD_COLOR_YUV420                   0x09
  52
  53#define BLIZZARD_VERSION_S1D13745               0x01    /* Hailstorm */
  54#define BLIZZARD_VERSION_S1D13744               0x02    /* Blizzard */
  55
  56#define MIPID_CMD_READ_DISP_ID          0x04
  57#define MIPID_CMD_READ_RED              0x06
  58#define MIPID_CMD_READ_GREEN            0x07
  59#define MIPID_CMD_READ_BLUE             0x08
  60#define MIPID_CMD_READ_DISP_STATUS      0x09
  61#define MIPID_CMD_RDDSDR                0x0F
  62#define MIPID_CMD_SLEEP_IN              0x10
  63#define MIPID_CMD_SLEEP_OUT             0x11
  64#define MIPID_CMD_DISP_OFF              0x28
  65#define MIPID_CMD_DISP_ON               0x29
  66
  67static struct panel_drv_data {
  68        struct mutex lock;
  69
  70        struct omap_dss_device *dssdev;
  71        struct spi_device *spidev;
  72        struct backlight_device *bldev;
  73
  74        int blizzard_ver;
  75} s_drv_data;
  76
  77
  78static inline
  79struct panel_n8x0_data *get_board_data(const struct omap_dss_device *dssdev)
  80{
  81        return dssdev->data;
  82}
  83
  84static inline
  85struct panel_drv_data *get_drv_data(const struct omap_dss_device *dssdev)
  86{
  87        return &s_drv_data;
  88}
  89
  90
  91static inline void blizzard_cmd(u8 cmd)
  92{
  93        omap_rfbi_write_command(&cmd, 1);
  94}
  95
  96static inline void blizzard_write(u8 cmd, const u8 *buf, int len)
  97{
  98        omap_rfbi_write_command(&cmd, 1);
  99        omap_rfbi_write_data(buf, len);
 100}
 101
 102static inline void blizzard_read(u8 cmd, u8 *buf, int len)
 103{
 104        omap_rfbi_write_command(&cmd, 1);
 105        omap_rfbi_read_data(buf, len);
 106}
 107
 108static u8 blizzard_read_reg(u8 cmd)
 109{
 110        u8 data;
 111        blizzard_read(cmd, &data, 1);
 112        return data;
 113}
 114
 115static void blizzard_ctrl_setup_update(struct omap_dss_device *dssdev,
 116                int x, int y, int w, int h)
 117{
 118        struct panel_drv_data *ddata = get_drv_data(dssdev);
 119        u8 tmp[18];
 120        int x_end, y_end;
 121
 122        x_end = x + w - 1;
 123        y_end = y + h - 1;
 124
 125        tmp[0] = x;
 126        tmp[1] = x >> 8;
 127        tmp[2] = y;
 128        tmp[3] = y >> 8;
 129        tmp[4] = x_end;
 130        tmp[5] = x_end >> 8;
 131        tmp[6] = y_end;
 132        tmp[7] = y_end >> 8;
 133
 134        /* scaling? */
 135        tmp[8] = x;
 136        tmp[9] = x >> 8;
 137        tmp[10] = y;
 138        tmp[11] = y >> 8;
 139        tmp[12] = x_end;
 140        tmp[13] = x_end >> 8;
 141        tmp[14] = y_end;
 142        tmp[15] = y_end >> 8;
 143
 144        tmp[16] = BLIZZARD_COLOR_RGB565;
 145
 146        if (ddata->blizzard_ver == BLIZZARD_VERSION_S1D13745)
 147                tmp[17] = BLIZZARD_SRC_WRITE_LCD_BACKGROUND;
 148        else
 149                tmp[17] = ddata->blizzard_ver == BLIZZARD_VERSION_S1D13744 ?
 150                        BLIZZARD_SRC_WRITE_LCD :
 151                        BLIZZARD_SRC_WRITE_LCD_DESTRUCTIVE;
 152
 153        omap_rfbi_configure(dssdev, 16, 8);
 154
 155        blizzard_write(BLIZZARD_INPUT_WIN_X_START_0, tmp, 18);
 156
 157        omap_rfbi_configure(dssdev, 16, 16);
 158}
 159
 160static void mipid_transfer(struct spi_device *spi, int cmd, const u8 *wbuf,
 161                int wlen, u8 *rbuf, int rlen)
 162{
 163        struct spi_message      m;
 164        struct spi_transfer     *x, xfer[4];
 165        u16                     w;
 166        int                     r;
 167
 168        spi_message_init(&m);
 169
 170        memset(xfer, 0, sizeof(xfer));
 171        x = &xfer[0];
 172
 173        cmd &=  0xff;
 174        x->tx_buf               = &cmd;
 175        x->bits_per_word        = 9;
 176        x->len                  = 2;
 177        spi_message_add_tail(x, &m);
 178
 179        if (wlen) {
 180                x++;
 181                x->tx_buf               = wbuf;
 182                x->len                  = wlen;
 183                x->bits_per_word        = 9;
 184                spi_message_add_tail(x, &m);
 185        }
 186
 187        if (rlen) {
 188                x++;
 189                x->rx_buf       = &w;
 190                x->len          = 1;
 191                spi_message_add_tail(x, &m);
 192
 193                if (rlen > 1) {
 194                        /* Arrange for the extra clock before the first
 195                         * data bit.
 196                         */
 197                        x->bits_per_word = 9;
 198                        x->len           = 2;
 199
 200                        x++;
 201                        x->rx_buf        = &rbuf[1];
 202                        x->len           = rlen - 1;
 203                        spi_message_add_tail(x, &m);
 204                }
 205        }
 206
 207        r = spi_sync(spi, &m);
 208        if (r < 0)
 209                dev_dbg(&spi->dev, "spi_sync %d\n", r);
 210
 211        if (rlen)
 212                rbuf[0] = w & 0xff;
 213}
 214
 215static inline void mipid_cmd(struct spi_device *spi, int cmd)
 216{
 217        mipid_transfer(spi, cmd, NULL, 0, NULL, 0);
 218}
 219
 220static inline void mipid_write(struct spi_device *spi,
 221                int reg, const u8 *buf, int len)
 222{
 223        mipid_transfer(spi, reg, buf, len, NULL, 0);
 224}
 225
 226static inline void mipid_read(struct spi_device *spi,
 227                int reg, u8 *buf, int len)
 228{
 229        mipid_transfer(spi, reg, NULL, 0, buf, len);
 230}
 231
 232static void set_data_lines(struct spi_device *spi, int data_lines)
 233{
 234        u16 par;
 235
 236        switch (data_lines) {
 237        case 16:
 238                par = 0x150;
 239                break;
 240        case 18:
 241                par = 0x160;
 242                break;
 243        case 24:
 244                par = 0x170;
 245                break;
 246        }
 247
 248        mipid_write(spi, 0x3a, (u8 *)&par, 2);
 249}
 250
 251static void send_init_string(struct spi_device *spi)
 252{
 253        u16 initpar[] = { 0x0102, 0x0100, 0x0100 };
 254        mipid_write(spi, 0xc2, (u8 *)initpar, sizeof(initpar));
 255}
 256
 257static void send_display_on(struct spi_device *spi)
 258{
 259        mipid_cmd(spi, MIPID_CMD_DISP_ON);
 260}
 261
 262static void send_display_off(struct spi_device *spi)
 263{
 264        mipid_cmd(spi, MIPID_CMD_DISP_OFF);
 265}
 266
 267static void send_sleep_out(struct spi_device *spi)
 268{
 269        mipid_cmd(spi, MIPID_CMD_SLEEP_OUT);
 270        msleep(120);
 271}
 272
 273static void send_sleep_in(struct spi_device *spi)
 274{
 275        mipid_cmd(spi, MIPID_CMD_SLEEP_IN);
 276        msleep(50);
 277}
 278
 279static int n8x0_panel_power_on(struct omap_dss_device *dssdev)
 280{
 281        int r;
 282        struct panel_n8x0_data *bdata = get_board_data(dssdev);
 283        struct panel_drv_data *ddata = get_drv_data(dssdev);
 284        struct spi_device *spi = ddata->spidev;
 285        u8 rev, conf;
 286        u8 display_id[3];
 287        const char *panel_name;
 288
 289        if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
 290                return 0;
 291
 292        gpio_direction_output(bdata->ctrl_pwrdown, 1);
 293
 294        if (bdata->platform_enable) {
 295                r = bdata->platform_enable(dssdev);
 296                if (r)
 297                        goto err_plat_en;
 298        }
 299
 300        r = omapdss_rfbi_display_enable(dssdev);
 301        if (r)
 302                goto err_rfbi_en;
 303
 304        rev = blizzard_read_reg(BLIZZARD_REV_CODE);
 305        conf = blizzard_read_reg(BLIZZARD_CONFIG);
 306
 307        switch (rev & 0xfc) {
 308        case 0x9c:
 309                ddata->blizzard_ver = BLIZZARD_VERSION_S1D13744;
 310                dev_info(&dssdev->dev, "s1d13744 LCD controller rev %d "
 311                        "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
 312                break;
 313        case 0xa4:
 314                ddata->blizzard_ver = BLIZZARD_VERSION_S1D13745;
 315                dev_info(&dssdev->dev, "s1d13745 LCD controller rev %d "
 316                        "initialized (CNF pins %x)\n", rev & 0x03, conf & 0x07);
 317                break;
 318        default:
 319                dev_err(&dssdev->dev, "invalid s1d1374x revision %02x\n", rev);
 320                r = -ENODEV;
 321                goto err_inv_chip;
 322        }
 323
 324        /* panel */
 325
 326        gpio_direction_output(bdata->panel_reset, 1);
 327
 328        mipid_read(spi, MIPID_CMD_READ_DISP_ID, display_id, 3);
 329        dev_dbg(&spi->dev, "MIPI display ID: %02x%02x%02x\n",
 330                        display_id[0], display_id[1], display_id[2]);
 331
 332        switch (display_id[0]) {
 333        case 0x45:
 334                panel_name = "lph8923";
 335                break;
 336        case 0x83:
 337                panel_name = "ls041y3";
 338                break;
 339        default:
 340                dev_err(&dssdev->dev, "invalid display ID 0x%x\n",
 341                                display_id[0]);
 342                r = -ENODEV;
 343                goto err_inv_panel;
 344        }
 345
 346        dev_info(&dssdev->dev, "%s rev %02x LCD detected\n",
 347                        panel_name, display_id[1]);
 348
 349        send_sleep_out(spi);
 350        send_init_string(spi);
 351        set_data_lines(spi, 24);
 352        send_display_on(spi);
 353
 354        return 0;
 355
 356err_inv_panel:
 357        /*
 358         * HACK: we should turn off the panel here, but there is some problem
 359         * with the initialization sequence, and we fail to init the panel if we
 360         * have turned it off
 361         */
 362        /* gpio_direction_output(bdata->panel_reset, 0); */
 363err_inv_chip:
 364        omapdss_rfbi_display_disable(dssdev);
 365err_rfbi_en:
 366        if (bdata->platform_disable)
 367                bdata->platform_disable(dssdev);
 368err_plat_en:
 369        gpio_direction_output(bdata->ctrl_pwrdown, 0);
 370        return r;
 371}
 372
 373static void n8x0_panel_power_off(struct omap_dss_device *dssdev)
 374{
 375        struct panel_n8x0_data *bdata = get_board_data(dssdev);
 376        struct panel_drv_data *ddata = get_drv_data(dssdev);
 377        struct spi_device *spi = ddata->spidev;
 378
 379        if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 380                return;
 381
 382        send_display_off(spi);
 383        send_sleep_in(spi);
 384
 385        if (bdata->platform_disable)
 386                bdata->platform_disable(dssdev);
 387
 388        /*
 389         * HACK: we should turn off the panel here, but there is some problem
 390         * with the initialization sequence, and we fail to init the panel if we
 391         * have turned it off
 392         */
 393        /* gpio_direction_output(bdata->panel_reset, 0); */
 394        gpio_direction_output(bdata->ctrl_pwrdown, 0);
 395        omapdss_rfbi_display_disable(dssdev);
 396}
 397
 398static const struct rfbi_timings n8x0_panel_timings = {
 399        .cs_on_time     = 0,
 400
 401        .we_on_time     = 9000,
 402        .we_off_time    = 18000,
 403        .we_cycle_time  = 36000,
 404
 405        .re_on_time     = 9000,
 406        .re_off_time    = 27000,
 407        .re_cycle_time  = 36000,
 408
 409        .access_time    = 27000,
 410        .cs_off_time    = 36000,
 411
 412        .cs_pulse_width = 0,
 413};
 414
 415static int n8x0_bl_update_status(struct backlight_device *dev)
 416{
 417        struct omap_dss_device *dssdev = dev_get_drvdata(&dev->dev);
 418        struct panel_n8x0_data *bdata = get_board_data(dssdev);
 419        struct panel_drv_data *ddata = get_drv_data(dssdev);
 420        int r;
 421        int level;
 422
 423        mutex_lock(&ddata->lock);
 424
 425        if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
 426                        dev->props.power == FB_BLANK_UNBLANK)
 427                level = dev->props.brightness;
 428        else
 429                level = 0;
 430
 431        dev_dbg(&dssdev->dev, "update brightness to %d\n", level);
 432
 433        if (!bdata->set_backlight)
 434                r = -EINVAL;
 435        else
 436                r = bdata->set_backlight(dssdev, level);
 437
 438        mutex_unlock(&ddata->lock);
 439
 440        return r;
 441}
 442
 443static int n8x0_bl_get_intensity(struct backlight_device *dev)
 444{
 445        if (dev->props.fb_blank == FB_BLANK_UNBLANK &&
 446                        dev->props.power == FB_BLANK_UNBLANK)
 447                return dev->props.brightness;
 448
 449        return 0;
 450}
 451
 452static const struct backlight_ops n8x0_bl_ops = {
 453        .get_brightness = n8x0_bl_get_intensity,
 454        .update_status  = n8x0_bl_update_status,
 455};
 456
 457static int n8x0_panel_probe(struct omap_dss_device *dssdev)
 458{
 459        struct panel_n8x0_data *bdata = get_board_data(dssdev);
 460        struct panel_drv_data *ddata;
 461        struct backlight_device *bldev;
 462        struct backlight_properties props;
 463        int r;
 464
 465        dev_dbg(&dssdev->dev, "probe\n");
 466
 467        if (!bdata)
 468                return -EINVAL;
 469
 470        s_drv_data.dssdev = dssdev;
 471
 472        ddata = &s_drv_data;
 473
 474        mutex_init(&ddata->lock);
 475
 476        dssdev->panel.config = OMAP_DSS_LCD_TFT;
 477        dssdev->panel.timings.x_res = 800;
 478        dssdev->panel.timings.y_res = 480;
 479        dssdev->ctrl.pixel_size = 16;
 480        dssdev->ctrl.rfbi_timings = n8x0_panel_timings;
 481
 482        memset(&props, 0, sizeof(props));
 483        props.max_brightness = 127;
 484        props.type = BACKLIGHT_PLATFORM;
 485        bldev = backlight_device_register(dev_name(&dssdev->dev), &dssdev->dev,
 486                        dssdev, &n8x0_bl_ops, &props);
 487        if (IS_ERR(bldev)) {
 488                r = PTR_ERR(bldev);
 489                dev_err(&dssdev->dev, "register backlight failed\n");
 490                return r;
 491        }
 492
 493        ddata->bldev = bldev;
 494
 495        bldev->props.fb_blank = FB_BLANK_UNBLANK;
 496        bldev->props.power = FB_BLANK_UNBLANK;
 497        bldev->props.brightness = 127;
 498
 499        n8x0_bl_update_status(bldev);
 500
 501        return 0;
 502}
 503
 504static void n8x0_panel_remove(struct omap_dss_device *dssdev)
 505{
 506        struct panel_drv_data *ddata = get_drv_data(dssdev);
 507        struct backlight_device *bldev;
 508
 509        dev_dbg(&dssdev->dev, "remove\n");
 510
 511        bldev = ddata->bldev;
 512        bldev->props.power = FB_BLANK_POWERDOWN;
 513        n8x0_bl_update_status(bldev);
 514        backlight_device_unregister(bldev);
 515
 516        dev_set_drvdata(&dssdev->dev, NULL);
 517}
 518
 519static int n8x0_panel_enable(struct omap_dss_device *dssdev)
 520{
 521        struct panel_drv_data *ddata = get_drv_data(dssdev);
 522        int r;
 523
 524        dev_dbg(&dssdev->dev, "enable\n");
 525
 526        mutex_lock(&ddata->lock);
 527
 528        rfbi_bus_lock();
 529
 530        r = n8x0_panel_power_on(dssdev);
 531
 532        rfbi_bus_unlock();
 533
 534        if (r) {
 535                mutex_unlock(&ddata->lock);
 536                return r;
 537        }
 538
 539        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 540
 541        mutex_unlock(&ddata->lock);
 542
 543        return 0;
 544}
 545
 546static void n8x0_panel_disable(struct omap_dss_device *dssdev)
 547{
 548        struct panel_drv_data *ddata = get_drv_data(dssdev);
 549
 550        dev_dbg(&dssdev->dev, "disable\n");
 551
 552        mutex_lock(&ddata->lock);
 553
 554        rfbi_bus_lock();
 555
 556        n8x0_panel_power_off(dssdev);
 557
 558        rfbi_bus_unlock();
 559
 560        dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
 561
 562        mutex_unlock(&ddata->lock);
 563}
 564
 565static int n8x0_panel_suspend(struct omap_dss_device *dssdev)
 566{
 567        struct panel_drv_data *ddata = get_drv_data(dssdev);
 568
 569        dev_dbg(&dssdev->dev, "suspend\n");
 570
 571        mutex_lock(&ddata->lock);
 572
 573        rfbi_bus_lock();
 574
 575        n8x0_panel_power_off(dssdev);
 576
 577        rfbi_bus_unlock();
 578
 579        dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
 580
 581        mutex_unlock(&ddata->lock);
 582
 583        return 0;
 584}
 585
 586static int n8x0_panel_resume(struct omap_dss_device *dssdev)
 587{
 588        struct panel_drv_data *ddata = get_drv_data(dssdev);
 589        int r;
 590
 591        dev_dbg(&dssdev->dev, "resume\n");
 592
 593        mutex_lock(&ddata->lock);
 594
 595        rfbi_bus_lock();
 596
 597        r = n8x0_panel_power_on(dssdev);
 598
 599        rfbi_bus_unlock();
 600
 601        if (r) {
 602                mutex_unlock(&ddata->lock);
 603                return r;
 604        }
 605
 606        dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 607
 608        mutex_unlock(&ddata->lock);
 609
 610        return 0;
 611}
 612
 613static void n8x0_panel_get_timings(struct omap_dss_device *dssdev,
 614                struct omap_video_timings *timings)
 615{
 616        *timings = dssdev->panel.timings;
 617}
 618
 619static void n8x0_panel_get_resolution(struct omap_dss_device *dssdev,
 620                u16 *xres, u16 *yres)
 621{
 622        *xres = dssdev->panel.timings.x_res;
 623        *yres = dssdev->panel.timings.y_res;
 624}
 625
 626static void update_done(void *data)
 627{
 628        rfbi_bus_unlock();
 629}
 630
 631static int n8x0_panel_update(struct omap_dss_device *dssdev,
 632                u16 x, u16 y, u16 w, u16 h)
 633{
 634        struct panel_drv_data *ddata = get_drv_data(dssdev);
 635
 636        dev_dbg(&dssdev->dev, "update\n");
 637
 638        mutex_lock(&ddata->lock);
 639        rfbi_bus_lock();
 640
 641        omap_rfbi_prepare_update(dssdev, &x, &y, &w, &h);
 642
 643        blizzard_ctrl_setup_update(dssdev, x, y, w, h);
 644
 645        omap_rfbi_update(dssdev, x, y, w, h, update_done, NULL);
 646
 647        mutex_unlock(&ddata->lock);
 648
 649        return 0;
 650}
 651
 652static int n8x0_panel_sync(struct omap_dss_device *dssdev)
 653{
 654        struct panel_drv_data *ddata = get_drv_data(dssdev);
 655
 656        dev_dbg(&dssdev->dev, "sync\n");
 657
 658        mutex_lock(&ddata->lock);
 659        rfbi_bus_lock();
 660        rfbi_bus_unlock();
 661        mutex_unlock(&ddata->lock);
 662
 663        return 0;
 664}
 665
 666static struct omap_dss_driver n8x0_panel_driver = {
 667        .probe          = n8x0_panel_probe,
 668        .remove         = n8x0_panel_remove,
 669
 670        .enable         = n8x0_panel_enable,
 671        .disable        = n8x0_panel_disable,
 672        .suspend        = n8x0_panel_suspend,
 673        .resume         = n8x0_panel_resume,
 674
 675        .update         = n8x0_panel_update,
 676        .sync           = n8x0_panel_sync,
 677
 678        .get_resolution = n8x0_panel_get_resolution,
 679        .get_recommended_bpp = omapdss_default_get_recommended_bpp,
 680
 681        .get_timings    = n8x0_panel_get_timings,
 682
 683        .driver         = {
 684                .name   = "n8x0_panel",
 685                .owner  = THIS_MODULE,
 686        },
 687};
 688
 689/* PANEL */
 690
 691static int mipid_spi_probe(struct spi_device *spi)
 692{
 693        dev_dbg(&spi->dev, "mipid_spi_probe\n");
 694
 695        spi->mode = SPI_MODE_0;
 696
 697        s_drv_data.spidev = spi;
 698
 699        return 0;
 700}
 701
 702static int mipid_spi_remove(struct spi_device *spi)
 703{
 704        dev_dbg(&spi->dev, "mipid_spi_remove\n");
 705        return 0;
 706}
 707
 708static struct spi_driver mipid_spi_driver = {
 709        .driver = {
 710                .name   = "lcd_mipid",
 711                .owner  = THIS_MODULE,
 712        },
 713        .probe  = mipid_spi_probe,
 714        .remove = __devexit_p(mipid_spi_remove),
 715};
 716
 717static int __init n8x0_panel_drv_init(void)
 718{
 719        int r;
 720
 721        r = spi_register_driver(&mipid_spi_driver);
 722        if (r) {
 723                pr_err("n8x0_panel: spi driver registration failed\n");
 724                return r;
 725        }
 726
 727        r = omap_dss_register_driver(&n8x0_panel_driver);
 728        if (r) {
 729                pr_err("n8x0_panel: dss driver registration failed\n");
 730                spi_unregister_driver(&mipid_spi_driver);
 731                return r;
 732        }
 733
 734        return 0;
 735}
 736
 737static void __exit n8x0_panel_drv_exit(void)
 738{
 739        spi_unregister_driver(&mipid_spi_driver);
 740
 741        omap_dss_unregister_driver(&n8x0_panel_driver);
 742}
 743
 744module_init(n8x0_panel_drv_init);
 745module_exit(n8x0_panel_drv_exit);
 746MODULE_LICENSE("GPL");
 747