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