linux/drivers/video/backlight/hx8357.c
<<
>>
Prefs
   1/*
   2 * Driver for the Himax HX-8357 LCD Controller
   3 *
   4 * Copyright 2012 Free Electrons
   5 *
   6 * Licensed under the GPLv2 or later.
   7 */
   8
   9#include <linux/delay.h>
  10#include <linux/lcd.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13#include <linux/of_device.h>
  14#include <linux/of_gpio.h>
  15#include <linux/spi/spi.h>
  16
  17#define HX8357_NUM_IM_PINS      3
  18
  19#define HX8357_SWRESET                  0x01
  20#define HX8357_GET_RED_CHANNEL          0x06
  21#define HX8357_GET_GREEN_CHANNEL        0x07
  22#define HX8357_GET_BLUE_CHANNEL         0x08
  23#define HX8357_GET_POWER_MODE           0x0a
  24#define HX8357_GET_MADCTL               0x0b
  25#define HX8357_GET_PIXEL_FORMAT         0x0c
  26#define HX8357_GET_DISPLAY_MODE         0x0d
  27#define HX8357_GET_SIGNAL_MODE          0x0e
  28#define HX8357_GET_DIAGNOSTIC_RESULT    0x0f
  29#define HX8357_ENTER_SLEEP_MODE         0x10
  30#define HX8357_EXIT_SLEEP_MODE          0x11
  31#define HX8357_ENTER_PARTIAL_MODE       0x12
  32#define HX8357_ENTER_NORMAL_MODE        0x13
  33#define HX8357_EXIT_INVERSION_MODE      0x20
  34#define HX8357_ENTER_INVERSION_MODE     0x21
  35#define HX8357_SET_DISPLAY_OFF          0x28
  36#define HX8357_SET_DISPLAY_ON           0x29
  37#define HX8357_SET_COLUMN_ADDRESS       0x2a
  38#define HX8357_SET_PAGE_ADDRESS         0x2b
  39#define HX8357_WRITE_MEMORY_START       0x2c
  40#define HX8357_READ_MEMORY_START        0x2e
  41#define HX8357_SET_PARTIAL_AREA         0x30
  42#define HX8357_SET_SCROLL_AREA          0x33
  43#define HX8357_SET_TEAR_OFF             0x34
  44#define HX8357_SET_TEAR_ON              0x35
  45#define HX8357_SET_ADDRESS_MODE         0x36
  46#define HX8357_SET_SCROLL_START         0x37
  47#define HX8357_EXIT_IDLE_MODE           0x38
  48#define HX8357_ENTER_IDLE_MODE          0x39
  49#define HX8357_SET_PIXEL_FORMAT         0x3a
  50#define HX8357_SET_PIXEL_FORMAT_DBI_3BIT        (0x1)
  51#define HX8357_SET_PIXEL_FORMAT_DBI_16BIT       (0x5)
  52#define HX8357_SET_PIXEL_FORMAT_DBI_18BIT       (0x6)
  53#define HX8357_SET_PIXEL_FORMAT_DPI_3BIT        (0x1 << 4)
  54#define HX8357_SET_PIXEL_FORMAT_DPI_16BIT       (0x5 << 4)
  55#define HX8357_SET_PIXEL_FORMAT_DPI_18BIT       (0x6 << 4)
  56#define HX8357_WRITE_MEMORY_CONTINUE    0x3c
  57#define HX8357_READ_MEMORY_CONTINUE     0x3e
  58#define HX8357_SET_TEAR_SCAN_LINES      0x44
  59#define HX8357_GET_SCAN_LINES           0x45
  60#define HX8357_READ_DDB_START           0xa1
  61#define HX8357_SET_DISPLAY_MODE         0xb4
  62#define HX8357_SET_DISPLAY_MODE_RGB_THROUGH     (0x3)
  63#define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE   (1 << 4)
  64#define HX8357_SET_PANEL_DRIVING        0xc0
  65#define HX8357_SET_DISPLAY_FRAME        0xc5
  66#define HX8357_SET_RGB                  0xc6
  67#define HX8357_SET_RGB_ENABLE_HIGH              (1 << 1)
  68#define HX8357_SET_GAMMA                0xc8
  69#define HX8357_SET_POWER                0xd0
  70#define HX8357_SET_VCOM                 0xd1
  71#define HX8357_SET_POWER_NORMAL         0xd2
  72#define HX8357_SET_PANEL_RELATED        0xe9
  73
  74#define HX8369_SET_DISPLAY_BRIGHTNESS           0x51
  75#define HX8369_WRITE_CABC_DISPLAY_VALUE         0x53
  76#define HX8369_WRITE_CABC_BRIGHT_CTRL           0x55
  77#define HX8369_WRITE_CABC_MIN_BRIGHTNESS        0x5e
  78#define HX8369_SET_POWER                        0xb1
  79#define HX8369_SET_DISPLAY_MODE                 0xb2
  80#define HX8369_SET_DISPLAY_WAVEFORM_CYC         0xb4
  81#define HX8369_SET_VCOM                         0xb6
  82#define HX8369_SET_EXTENSION_COMMAND            0xb9
  83#define HX8369_SET_GIP                          0xd5
  84#define HX8369_SET_GAMMA_CURVE_RELATED          0xe0
  85
  86struct hx8357_data {
  87        unsigned                im_pins[HX8357_NUM_IM_PINS];
  88        unsigned                reset;
  89        struct spi_device       *spi;
  90        int                     state;
  91        bool                    use_im_pins;
  92};
  93
  94static u8 hx8357_seq_power[] = {
  95        HX8357_SET_POWER, 0x44, 0x41, 0x06,
  96};
  97
  98static u8 hx8357_seq_vcom[] = {
  99        HX8357_SET_VCOM, 0x40, 0x10,
 100};
 101
 102static u8 hx8357_seq_power_normal[] = {
 103        HX8357_SET_POWER_NORMAL, 0x05, 0x12,
 104};
 105
 106static u8 hx8357_seq_panel_driving[] = {
 107        HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
 108};
 109
 110static u8 hx8357_seq_display_frame[] = {
 111        HX8357_SET_DISPLAY_FRAME, 0x0c,
 112};
 113
 114static u8 hx8357_seq_panel_related[] = {
 115        HX8357_SET_PANEL_RELATED, 0x01,
 116};
 117
 118static u8 hx8357_seq_undefined1[] = {
 119        0xea, 0x03, 0x00, 0x00,
 120};
 121
 122static u8 hx8357_seq_undefined2[] = {
 123        0xeb, 0x40, 0x54, 0x26, 0xdb,
 124};
 125
 126static u8 hx8357_seq_gamma[] = {
 127        HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
 128        0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
 129};
 130
 131static u8 hx8357_seq_address_mode[] = {
 132        HX8357_SET_ADDRESS_MODE, 0xc0,
 133};
 134
 135static u8 hx8357_seq_pixel_format[] = {
 136        HX8357_SET_PIXEL_FORMAT,
 137        HX8357_SET_PIXEL_FORMAT_DPI_18BIT |
 138        HX8357_SET_PIXEL_FORMAT_DBI_18BIT,
 139};
 140
 141static u8 hx8357_seq_column_address[] = {
 142        HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
 143};
 144
 145static u8 hx8357_seq_page_address[] = {
 146        HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
 147};
 148
 149static u8 hx8357_seq_rgb[] = {
 150        HX8357_SET_RGB, 0x02,
 151};
 152
 153static u8 hx8357_seq_display_mode[] = {
 154        HX8357_SET_DISPLAY_MODE,
 155        HX8357_SET_DISPLAY_MODE_RGB_THROUGH |
 156        HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
 157};
 158
 159static u8 hx8369_seq_write_CABC_min_brightness[] = {
 160        HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00,
 161};
 162
 163static u8 hx8369_seq_write_CABC_control[] = {
 164        HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24,
 165};
 166
 167static u8 hx8369_seq_set_display_brightness[] = {
 168        HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF,
 169};
 170
 171static u8 hx8369_seq_write_CABC_control_setting[] = {
 172        HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02,
 173};
 174
 175static u8 hx8369_seq_extension_command[] = {
 176        HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69,
 177};
 178
 179static u8 hx8369_seq_display_related[] = {
 180        HX8369_SET_DISPLAY_MODE, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
 181        0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
 182};
 183
 184static u8 hx8369_seq_panel_waveform_cycle[] = {
 185        HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02,
 186};
 187
 188static u8 hx8369_seq_set_address_mode[] = {
 189        HX8357_SET_ADDRESS_MODE, 0x00,
 190};
 191
 192static u8 hx8369_seq_vcom[] = {
 193        HX8369_SET_VCOM, 0x3e, 0x3e,
 194};
 195
 196static u8 hx8369_seq_gip[] = {
 197        HX8369_SET_GIP, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
 198        0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
 199        0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
 200};
 201
 202static u8 hx8369_seq_power[] = {
 203        HX8369_SET_POWER, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
 204        0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
 205};
 206
 207static u8 hx8369_seq_gamma_curve_related[] = {
 208        HX8369_SET_GAMMA_CURVE_RELATED, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
 209        0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
 210        0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
 211        0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
 212};
 213
 214static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
 215                                u8 *txbuf, u16 txlen,
 216                                u8 *rxbuf, u16 rxlen)
 217{
 218        struct hx8357_data *lcd = lcd_get_data(lcdev);
 219        struct spi_message msg;
 220        struct spi_transfer xfer[2];
 221        u16 *local_txbuf = NULL;
 222        int ret = 0;
 223
 224        memset(xfer, 0, sizeof(xfer));
 225        spi_message_init(&msg);
 226
 227        if (txlen) {
 228                int i;
 229
 230                local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL);
 231
 232                if (!local_txbuf)
 233                        return -ENOMEM;
 234
 235                for (i = 0; i < txlen; i++) {
 236                        local_txbuf[i] = txbuf[i];
 237                        if (i > 0)
 238                                local_txbuf[i] |= 1 << 8;
 239                }
 240
 241                xfer[0].len = 2 * txlen;
 242                xfer[0].bits_per_word = 9;
 243                xfer[0].tx_buf = local_txbuf;
 244                spi_message_add_tail(&xfer[0], &msg);
 245        }
 246
 247        if (rxlen) {
 248                xfer[1].len = rxlen;
 249                xfer[1].bits_per_word = 8;
 250                xfer[1].rx_buf = rxbuf;
 251                spi_message_add_tail(&xfer[1], &msg);
 252        }
 253
 254        ret = spi_sync(lcd->spi, &msg);
 255        if (ret < 0)
 256                dev_err(&lcdev->dev, "Couldn't send SPI data\n");
 257
 258        if (txlen)
 259                kfree(local_txbuf);
 260
 261        return ret;
 262}
 263
 264static inline int hx8357_spi_write_array(struct lcd_device *lcdev,
 265                                        u8 *value, u8 len)
 266{
 267        return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0);
 268}
 269
 270static inline int hx8357_spi_write_byte(struct lcd_device *lcdev,
 271                                        u8 value)
 272{
 273        return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0);
 274}
 275
 276static int hx8357_enter_standby(struct lcd_device *lcdev)
 277{
 278        int ret;
 279
 280        ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF);
 281        if (ret < 0)
 282                return ret;
 283
 284        usleep_range(10000, 12000);
 285
 286        ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE);
 287        if (ret < 0)
 288                return ret;
 289
 290        /*
 291         * The controller needs 120ms when entering in sleep mode before we can
 292         * send the command to go off sleep mode
 293         */
 294        msleep(120);
 295
 296        return 0;
 297}
 298
 299static int hx8357_exit_standby(struct lcd_device *lcdev)
 300{
 301        int ret;
 302
 303        ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
 304        if (ret < 0)
 305                return ret;
 306
 307        /*
 308         * The controller needs 120ms when exiting from sleep mode before we
 309         * can send the command to enter in sleep mode
 310         */
 311        msleep(120);
 312
 313        ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
 314        if (ret < 0)
 315                return ret;
 316
 317        return 0;
 318}
 319
 320static void hx8357_lcd_reset(struct lcd_device *lcdev)
 321{
 322        struct hx8357_data *lcd = lcd_get_data(lcdev);
 323
 324        /* Reset the screen */
 325        gpio_set_value(lcd->reset, 1);
 326        usleep_range(10000, 12000);
 327        gpio_set_value(lcd->reset, 0);
 328        usleep_range(10000, 12000);
 329        gpio_set_value(lcd->reset, 1);
 330
 331        /* The controller needs 120ms to recover from reset */
 332        msleep(120);
 333}
 334
 335static int hx8357_lcd_init(struct lcd_device *lcdev)
 336{
 337        struct hx8357_data *lcd = lcd_get_data(lcdev);
 338        int ret;
 339
 340        /*
 341         * Set the interface selection pins to SPI mode, with three
 342         * wires
 343         */
 344        if (lcd->use_im_pins) {
 345                gpio_set_value_cansleep(lcd->im_pins[0], 1);
 346                gpio_set_value_cansleep(lcd->im_pins[1], 0);
 347                gpio_set_value_cansleep(lcd->im_pins[2], 1);
 348        }
 349
 350        ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
 351                                ARRAY_SIZE(hx8357_seq_power));
 352        if (ret < 0)
 353                return ret;
 354
 355        ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom,
 356                                ARRAY_SIZE(hx8357_seq_vcom));
 357        if (ret < 0)
 358                return ret;
 359
 360        ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal,
 361                                ARRAY_SIZE(hx8357_seq_power_normal));
 362        if (ret < 0)
 363                return ret;
 364
 365        ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving,
 366                                ARRAY_SIZE(hx8357_seq_panel_driving));
 367        if (ret < 0)
 368                return ret;
 369
 370        ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame,
 371                                ARRAY_SIZE(hx8357_seq_display_frame));
 372        if (ret < 0)
 373                return ret;
 374
 375        ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related,
 376                                ARRAY_SIZE(hx8357_seq_panel_related));
 377        if (ret < 0)
 378                return ret;
 379
 380        ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1,
 381                                ARRAY_SIZE(hx8357_seq_undefined1));
 382        if (ret < 0)
 383                return ret;
 384
 385        ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2,
 386                                ARRAY_SIZE(hx8357_seq_undefined2));
 387        if (ret < 0)
 388                return ret;
 389
 390        ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma,
 391                                ARRAY_SIZE(hx8357_seq_gamma));
 392        if (ret < 0)
 393                return ret;
 394
 395        ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode,
 396                                ARRAY_SIZE(hx8357_seq_address_mode));
 397        if (ret < 0)
 398                return ret;
 399
 400        ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format,
 401                                ARRAY_SIZE(hx8357_seq_pixel_format));
 402        if (ret < 0)
 403                return ret;
 404
 405        ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address,
 406                                ARRAY_SIZE(hx8357_seq_column_address));
 407        if (ret < 0)
 408                return ret;
 409
 410        ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address,
 411                                ARRAY_SIZE(hx8357_seq_page_address));
 412        if (ret < 0)
 413                return ret;
 414
 415        ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb,
 416                                ARRAY_SIZE(hx8357_seq_rgb));
 417        if (ret < 0)
 418                return ret;
 419
 420        ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode,
 421                                ARRAY_SIZE(hx8357_seq_display_mode));
 422        if (ret < 0)
 423                return ret;
 424
 425        ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
 426        if (ret < 0)
 427                return ret;
 428
 429        /*
 430         * The controller needs 120ms to fully recover from exiting sleep mode
 431         */
 432        msleep(120);
 433
 434        ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
 435        if (ret < 0)
 436                return ret;
 437
 438        usleep_range(5000, 7000);
 439
 440        ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START);
 441        if (ret < 0)
 442                return ret;
 443
 444        return 0;
 445}
 446
 447static int hx8369_lcd_init(struct lcd_device *lcdev)
 448{
 449        int ret;
 450
 451        ret = hx8357_spi_write_array(lcdev, hx8369_seq_extension_command,
 452                                ARRAY_SIZE(hx8369_seq_extension_command));
 453        if (ret < 0)
 454                return ret;
 455        usleep_range(10000, 12000);
 456
 457        ret = hx8357_spi_write_array(lcdev, hx8369_seq_display_related,
 458                                ARRAY_SIZE(hx8369_seq_display_related));
 459        if (ret < 0)
 460                return ret;
 461
 462        ret = hx8357_spi_write_array(lcdev, hx8369_seq_panel_waveform_cycle,
 463                                ARRAY_SIZE(hx8369_seq_panel_waveform_cycle));
 464        if (ret < 0)
 465                return ret;
 466
 467        ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_address_mode,
 468                                ARRAY_SIZE(hx8369_seq_set_address_mode));
 469        if (ret < 0)
 470                return ret;
 471
 472        ret = hx8357_spi_write_array(lcdev, hx8369_seq_vcom,
 473                                ARRAY_SIZE(hx8369_seq_vcom));
 474        if (ret < 0)
 475                return ret;
 476
 477        ret = hx8357_spi_write_array(lcdev, hx8369_seq_gip,
 478                                ARRAY_SIZE(hx8369_seq_gip));
 479        if (ret < 0)
 480                return ret;
 481
 482        ret = hx8357_spi_write_array(lcdev, hx8369_seq_power,
 483                                ARRAY_SIZE(hx8369_seq_power));
 484        if (ret < 0)
 485                return ret;
 486
 487        ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
 488        if (ret < 0)
 489                return ret;
 490
 491        /*
 492         * The controller needs 120ms to fully recover from exiting sleep mode
 493         */
 494        msleep(120);
 495
 496        ret = hx8357_spi_write_array(lcdev, hx8369_seq_gamma_curve_related,
 497                                ARRAY_SIZE(hx8369_seq_gamma_curve_related));
 498        if (ret < 0)
 499                return ret;
 500
 501        ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
 502        if (ret < 0)
 503                return ret;
 504        usleep_range(1000, 1200);
 505
 506        ret = hx8357_spi_write_array(lcdev, hx8369_seq_write_CABC_control,
 507                                ARRAY_SIZE(hx8369_seq_write_CABC_control));
 508        if (ret < 0)
 509                return ret;
 510        usleep_range(10000, 12000);
 511
 512        ret = hx8357_spi_write_array(lcdev,
 513                        hx8369_seq_write_CABC_control_setting,
 514                        ARRAY_SIZE(hx8369_seq_write_CABC_control_setting));
 515        if (ret < 0)
 516                return ret;
 517
 518        ret = hx8357_spi_write_array(lcdev,
 519                        hx8369_seq_write_CABC_min_brightness,
 520                        ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness));
 521        if (ret < 0)
 522                return ret;
 523        usleep_range(10000, 12000);
 524
 525        ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_display_brightness,
 526                                ARRAY_SIZE(hx8369_seq_set_display_brightness));
 527        if (ret < 0)
 528                return ret;
 529
 530        ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
 531        if (ret < 0)
 532                return ret;
 533
 534        return 0;
 535}
 536
 537#define POWER_IS_ON(pwr)        ((pwr) <= FB_BLANK_NORMAL)
 538
 539static int hx8357_set_power(struct lcd_device *lcdev, int power)
 540{
 541        struct hx8357_data *lcd = lcd_get_data(lcdev);
 542        int ret = 0;
 543
 544        if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state))
 545                ret = hx8357_exit_standby(lcdev);
 546        else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state))
 547                ret = hx8357_enter_standby(lcdev);
 548
 549        if (ret == 0)
 550                lcd->state = power;
 551        else
 552                dev_warn(&lcdev->dev, "failed to set power mode %d\n", power);
 553
 554        return ret;
 555}
 556
 557static int hx8357_get_power(struct lcd_device *lcdev)
 558{
 559        struct hx8357_data *lcd = lcd_get_data(lcdev);
 560
 561        return lcd->state;
 562}
 563
 564static struct lcd_ops hx8357_ops = {
 565        .set_power      = hx8357_set_power,
 566        .get_power      = hx8357_get_power,
 567};
 568
 569static const struct of_device_id hx8357_dt_ids[] = {
 570        {
 571                .compatible = "himax,hx8357",
 572                .data = hx8357_lcd_init,
 573        },
 574        {
 575                .compatible = "himax,hx8369",
 576                .data = hx8369_lcd_init,
 577        },
 578        {},
 579};
 580MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
 581
 582static int hx8357_probe(struct spi_device *spi)
 583{
 584        struct lcd_device *lcdev;
 585        struct hx8357_data *lcd;
 586        const struct of_device_id *match;
 587        int i, ret;
 588
 589        lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
 590        if (!lcd)
 591                return -ENOMEM;
 592
 593        ret = spi_setup(spi);
 594        if (ret < 0) {
 595                dev_err(&spi->dev, "SPI setup failed.\n");
 596                return ret;
 597        }
 598
 599        lcd->spi = spi;
 600
 601        match = of_match_device(hx8357_dt_ids, &spi->dev);
 602        if (!match || !match->data)
 603                return -EINVAL;
 604
 605        lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
 606        if (!gpio_is_valid(lcd->reset)) {
 607                dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
 608                return -EINVAL;
 609        }
 610
 611        ret = devm_gpio_request_one(&spi->dev, lcd->reset,
 612                                    GPIOF_OUT_INIT_HIGH,
 613                                    "hx8357-reset");
 614        if (ret) {
 615                dev_err(&spi->dev,
 616                        "failed to request gpio %d: %d\n",
 617                        lcd->reset, ret);
 618                return -EINVAL;
 619        }
 620
 621        if (of_find_property(spi->dev.of_node, "im-gpios", NULL)) {
 622                lcd->use_im_pins = 1;
 623
 624                for (i = 0; i < HX8357_NUM_IM_PINS; i++) {
 625                        lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node,
 626                                                            "im-gpios", i);
 627                        if (lcd->im_pins[i] == -EPROBE_DEFER) {
 628                                dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n");
 629                                return -EPROBE_DEFER;
 630                        }
 631                        if (!gpio_is_valid(lcd->im_pins[i])) {
 632                                dev_err(&spi->dev, "Missing dt property: im-gpios\n");
 633                                return -EINVAL;
 634                        }
 635
 636                        ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i],
 637                                                    GPIOF_OUT_INIT_LOW,
 638                                                    "im_pins");
 639                        if (ret) {
 640                                dev_err(&spi->dev, "failed to request gpio %d: %d\n",
 641                                        lcd->im_pins[i], ret);
 642                                return -EINVAL;
 643                        }
 644                }
 645        } else {
 646                lcd->use_im_pins = 0;
 647        }
 648
 649        lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
 650                                        &hx8357_ops);
 651        if (IS_ERR(lcdev)) {
 652                ret = PTR_ERR(lcdev);
 653                return ret;
 654        }
 655        spi_set_drvdata(spi, lcdev);
 656
 657        hx8357_lcd_reset(lcdev);
 658
 659        ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
 660        if (ret) {
 661                dev_err(&spi->dev, "Couldn't initialize panel\n");
 662                return ret;
 663        }
 664
 665        dev_info(&spi->dev, "Panel probed\n");
 666
 667        return 0;
 668}
 669
 670static struct spi_driver hx8357_driver = {
 671        .probe  = hx8357_probe,
 672        .driver = {
 673                .name = "hx8357",
 674                .of_match_table = hx8357_dt_ids,
 675        },
 676};
 677
 678module_spi_driver(hx8357_driver);
 679
 680MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
 681MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
 682MODULE_LICENSE("GPL");
 683