Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Driver for the Himax HX-8357 LCD Controller
0004  *
0005  * Copyright 2012 Free Electrons
0006  */
0007 
0008 #include <linux/delay.h>
0009 #include <linux/lcd.h>
0010 #include <linux/module.h>
0011 #include <linux/of.h>
0012 #include <linux/of_device.h>
0013 #include <linux/of_gpio.h>
0014 #include <linux/spi/spi.h>
0015 
0016 #define HX8357_NUM_IM_PINS  3
0017 
0018 #define HX8357_SWRESET          0x01
0019 #define HX8357_GET_RED_CHANNEL      0x06
0020 #define HX8357_GET_GREEN_CHANNEL    0x07
0021 #define HX8357_GET_BLUE_CHANNEL     0x08
0022 #define HX8357_GET_POWER_MODE       0x0a
0023 #define HX8357_GET_MADCTL       0x0b
0024 #define HX8357_GET_PIXEL_FORMAT     0x0c
0025 #define HX8357_GET_DISPLAY_MODE     0x0d
0026 #define HX8357_GET_SIGNAL_MODE      0x0e
0027 #define HX8357_GET_DIAGNOSTIC_RESULT    0x0f
0028 #define HX8357_ENTER_SLEEP_MODE     0x10
0029 #define HX8357_EXIT_SLEEP_MODE      0x11
0030 #define HX8357_ENTER_PARTIAL_MODE   0x12
0031 #define HX8357_ENTER_NORMAL_MODE    0x13
0032 #define HX8357_EXIT_INVERSION_MODE  0x20
0033 #define HX8357_ENTER_INVERSION_MODE 0x21
0034 #define HX8357_SET_DISPLAY_OFF      0x28
0035 #define HX8357_SET_DISPLAY_ON       0x29
0036 #define HX8357_SET_COLUMN_ADDRESS   0x2a
0037 #define HX8357_SET_PAGE_ADDRESS     0x2b
0038 #define HX8357_WRITE_MEMORY_START   0x2c
0039 #define HX8357_READ_MEMORY_START    0x2e
0040 #define HX8357_SET_PARTIAL_AREA     0x30
0041 #define HX8357_SET_SCROLL_AREA      0x33
0042 #define HX8357_SET_TEAR_OFF     0x34
0043 #define HX8357_SET_TEAR_ON      0x35
0044 #define HX8357_SET_ADDRESS_MODE     0x36
0045 #define HX8357_SET_SCROLL_START     0x37
0046 #define HX8357_EXIT_IDLE_MODE       0x38
0047 #define HX8357_ENTER_IDLE_MODE      0x39
0048 #define HX8357_SET_PIXEL_FORMAT     0x3a
0049 #define HX8357_SET_PIXEL_FORMAT_DBI_3BIT    (0x1)
0050 #define HX8357_SET_PIXEL_FORMAT_DBI_16BIT   (0x5)
0051 #define HX8357_SET_PIXEL_FORMAT_DBI_18BIT   (0x6)
0052 #define HX8357_SET_PIXEL_FORMAT_DPI_3BIT    (0x1 << 4)
0053 #define HX8357_SET_PIXEL_FORMAT_DPI_16BIT   (0x5 << 4)
0054 #define HX8357_SET_PIXEL_FORMAT_DPI_18BIT   (0x6 << 4)
0055 #define HX8357_WRITE_MEMORY_CONTINUE    0x3c
0056 #define HX8357_READ_MEMORY_CONTINUE 0x3e
0057 #define HX8357_SET_TEAR_SCAN_LINES  0x44
0058 #define HX8357_GET_SCAN_LINES       0x45
0059 #define HX8357_READ_DDB_START       0xa1
0060 #define HX8357_SET_DISPLAY_MODE     0xb4
0061 #define HX8357_SET_DISPLAY_MODE_RGB_THROUGH (0x3)
0062 #define HX8357_SET_DISPLAY_MODE_RGB_INTERFACE   (1 << 4)
0063 #define HX8357_SET_PANEL_DRIVING    0xc0
0064 #define HX8357_SET_DISPLAY_FRAME    0xc5
0065 #define HX8357_SET_RGB          0xc6
0066 #define HX8357_SET_RGB_ENABLE_HIGH      (1 << 1)
0067 #define HX8357_SET_GAMMA        0xc8
0068 #define HX8357_SET_POWER        0xd0
0069 #define HX8357_SET_VCOM         0xd1
0070 #define HX8357_SET_POWER_NORMAL     0xd2
0071 #define HX8357_SET_PANEL_RELATED    0xe9
0072 
0073 #define HX8369_SET_DISPLAY_BRIGHTNESS       0x51
0074 #define HX8369_WRITE_CABC_DISPLAY_VALUE     0x53
0075 #define HX8369_WRITE_CABC_BRIGHT_CTRL       0x55
0076 #define HX8369_WRITE_CABC_MIN_BRIGHTNESS    0x5e
0077 #define HX8369_SET_POWER            0xb1
0078 #define HX8369_SET_DISPLAY_MODE         0xb2
0079 #define HX8369_SET_DISPLAY_WAVEFORM_CYC     0xb4
0080 #define HX8369_SET_VCOM             0xb6
0081 #define HX8369_SET_EXTENSION_COMMAND        0xb9
0082 #define HX8369_SET_GIP              0xd5
0083 #define HX8369_SET_GAMMA_CURVE_RELATED      0xe0
0084 
0085 struct hx8357_data {
0086     unsigned        im_pins[HX8357_NUM_IM_PINS];
0087     unsigned        reset;
0088     struct spi_device   *spi;
0089     int         state;
0090     bool            use_im_pins;
0091 };
0092 
0093 static u8 hx8357_seq_power[] = {
0094     HX8357_SET_POWER, 0x44, 0x41, 0x06,
0095 };
0096 
0097 static u8 hx8357_seq_vcom[] = {
0098     HX8357_SET_VCOM, 0x40, 0x10,
0099 };
0100 
0101 static u8 hx8357_seq_power_normal[] = {
0102     HX8357_SET_POWER_NORMAL, 0x05, 0x12,
0103 };
0104 
0105 static u8 hx8357_seq_panel_driving[] = {
0106     HX8357_SET_PANEL_DRIVING, 0x14, 0x3b, 0x00, 0x02, 0x11,
0107 };
0108 
0109 static u8 hx8357_seq_display_frame[] = {
0110     HX8357_SET_DISPLAY_FRAME, 0x0c,
0111 };
0112 
0113 static u8 hx8357_seq_panel_related[] = {
0114     HX8357_SET_PANEL_RELATED, 0x01,
0115 };
0116 
0117 static u8 hx8357_seq_undefined1[] = {
0118     0xea, 0x03, 0x00, 0x00,
0119 };
0120 
0121 static u8 hx8357_seq_undefined2[] = {
0122     0xeb, 0x40, 0x54, 0x26, 0xdb,
0123 };
0124 
0125 static u8 hx8357_seq_gamma[] = {
0126     HX8357_SET_GAMMA, 0x00, 0x15, 0x00, 0x22, 0x00,
0127     0x08, 0x77, 0x26, 0x77, 0x22, 0x04, 0x00,
0128 };
0129 
0130 static u8 hx8357_seq_address_mode[] = {
0131     HX8357_SET_ADDRESS_MODE, 0xc0,
0132 };
0133 
0134 static u8 hx8357_seq_pixel_format[] = {
0135     HX8357_SET_PIXEL_FORMAT,
0136     HX8357_SET_PIXEL_FORMAT_DPI_18BIT |
0137     HX8357_SET_PIXEL_FORMAT_DBI_18BIT,
0138 };
0139 
0140 static u8 hx8357_seq_column_address[] = {
0141     HX8357_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0x3f,
0142 };
0143 
0144 static u8 hx8357_seq_page_address[] = {
0145     HX8357_SET_PAGE_ADDRESS, 0x00, 0x00, 0x01, 0xdf,
0146 };
0147 
0148 static u8 hx8357_seq_rgb[] = {
0149     HX8357_SET_RGB, 0x02,
0150 };
0151 
0152 static u8 hx8357_seq_display_mode[] = {
0153     HX8357_SET_DISPLAY_MODE,
0154     HX8357_SET_DISPLAY_MODE_RGB_THROUGH |
0155     HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
0156 };
0157 
0158 static u8 hx8369_seq_write_CABC_min_brightness[] = {
0159     HX8369_WRITE_CABC_MIN_BRIGHTNESS, 0x00,
0160 };
0161 
0162 static u8 hx8369_seq_write_CABC_control[] = {
0163     HX8369_WRITE_CABC_DISPLAY_VALUE, 0x24,
0164 };
0165 
0166 static u8 hx8369_seq_set_display_brightness[] = {
0167     HX8369_SET_DISPLAY_BRIGHTNESS, 0xFF,
0168 };
0169 
0170 static u8 hx8369_seq_write_CABC_control_setting[] = {
0171     HX8369_WRITE_CABC_BRIGHT_CTRL, 0x02,
0172 };
0173 
0174 static u8 hx8369_seq_extension_command[] = {
0175     HX8369_SET_EXTENSION_COMMAND, 0xff, 0x83, 0x69,
0176 };
0177 
0178 static u8 hx8369_seq_display_related[] = {
0179     HX8369_SET_DISPLAY_MODE, 0x00, 0x2b, 0x03, 0x03, 0x70, 0x00,
0180     0xff, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x01,
0181 };
0182 
0183 static u8 hx8369_seq_panel_waveform_cycle[] = {
0184     HX8369_SET_DISPLAY_WAVEFORM_CYC, 0x0a, 0x1d, 0x80, 0x06, 0x02,
0185 };
0186 
0187 static u8 hx8369_seq_set_address_mode[] = {
0188     HX8357_SET_ADDRESS_MODE, 0x00,
0189 };
0190 
0191 static u8 hx8369_seq_vcom[] = {
0192     HX8369_SET_VCOM, 0x3e, 0x3e,
0193 };
0194 
0195 static u8 hx8369_seq_gip[] = {
0196     HX8369_SET_GIP, 0x00, 0x01, 0x03, 0x25, 0x01, 0x02, 0x28, 0x70,
0197     0x11, 0x13, 0x00, 0x00, 0x40, 0x26, 0x51, 0x37, 0x00, 0x00, 0x71,
0198     0x35, 0x60, 0x24, 0x07, 0x0f, 0x04, 0x04,
0199 };
0200 
0201 static u8 hx8369_seq_power[] = {
0202     HX8369_SET_POWER, 0x01, 0x00, 0x34, 0x03, 0x00, 0x11, 0x11, 0x32,
0203     0x2f, 0x3f, 0x3f, 0x01, 0x3a, 0x01, 0xe6, 0xe6, 0xe6, 0xe6, 0xe6,
0204 };
0205 
0206 static u8 hx8369_seq_gamma_curve_related[] = {
0207     HX8369_SET_GAMMA_CURVE_RELATED, 0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d,
0208     0x2e, 0x4a, 0x08, 0x0e, 0x0f, 0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
0209     0x00, 0x0d, 0x19, 0x2f, 0x3b, 0x3d, 0x2e, 0x4a, 0x08, 0x0e, 0x0f,
0210     0x14, 0x16, 0x14, 0x14, 0x14, 0x1e,
0211 };
0212 
0213 static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
0214                 u8 *txbuf, u16 txlen,
0215                 u8 *rxbuf, u16 rxlen)
0216 {
0217     struct hx8357_data *lcd = lcd_get_data(lcdev);
0218     struct spi_message msg;
0219     struct spi_transfer xfer[2];
0220     u16 *local_txbuf = NULL;
0221     int ret = 0;
0222 
0223     memset(xfer, 0, sizeof(xfer));
0224     spi_message_init(&msg);
0225 
0226     if (txlen) {
0227         int i;
0228 
0229         local_txbuf = kcalloc(txlen, sizeof(*local_txbuf), GFP_KERNEL);
0230 
0231         if (!local_txbuf)
0232             return -ENOMEM;
0233 
0234         for (i = 0; i < txlen; i++) {
0235             local_txbuf[i] = txbuf[i];
0236             if (i > 0)
0237                 local_txbuf[i] |= 1 << 8;
0238         }
0239 
0240         xfer[0].len = 2 * txlen;
0241         xfer[0].bits_per_word = 9;
0242         xfer[0].tx_buf = local_txbuf;
0243         spi_message_add_tail(&xfer[0], &msg);
0244     }
0245 
0246     if (rxlen) {
0247         xfer[1].len = rxlen;
0248         xfer[1].bits_per_word = 8;
0249         xfer[1].rx_buf = rxbuf;
0250         spi_message_add_tail(&xfer[1], &msg);
0251     }
0252 
0253     ret = spi_sync(lcd->spi, &msg);
0254     if (ret < 0)
0255         dev_err(&lcdev->dev, "Couldn't send SPI data\n");
0256 
0257     if (txlen)
0258         kfree(local_txbuf);
0259 
0260     return ret;
0261 }
0262 
0263 static inline int hx8357_spi_write_array(struct lcd_device *lcdev,
0264                     u8 *value, u8 len)
0265 {
0266     return hx8357_spi_write_then_read(lcdev, value, len, NULL, 0);
0267 }
0268 
0269 static inline int hx8357_spi_write_byte(struct lcd_device *lcdev,
0270                     u8 value)
0271 {
0272     return hx8357_spi_write_then_read(lcdev, &value, 1, NULL, 0);
0273 }
0274 
0275 static int hx8357_enter_standby(struct lcd_device *lcdev)
0276 {
0277     int ret;
0278 
0279     ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_OFF);
0280     if (ret < 0)
0281         return ret;
0282 
0283     usleep_range(10000, 12000);
0284 
0285     ret = hx8357_spi_write_byte(lcdev, HX8357_ENTER_SLEEP_MODE);
0286     if (ret < 0)
0287         return ret;
0288 
0289     /*
0290      * The controller needs 120ms when entering in sleep mode before we can
0291      * send the command to go off sleep mode
0292      */
0293     msleep(120);
0294 
0295     return 0;
0296 }
0297 
0298 static int hx8357_exit_standby(struct lcd_device *lcdev)
0299 {
0300     int ret;
0301 
0302     ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
0303     if (ret < 0)
0304         return ret;
0305 
0306     /*
0307      * The controller needs 120ms when exiting from sleep mode before we
0308      * can send the command to enter in sleep mode
0309      */
0310     msleep(120);
0311 
0312     ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
0313     if (ret < 0)
0314         return ret;
0315 
0316     return 0;
0317 }
0318 
0319 static void hx8357_lcd_reset(struct lcd_device *lcdev)
0320 {
0321     struct hx8357_data *lcd = lcd_get_data(lcdev);
0322 
0323     /* Reset the screen */
0324     gpio_set_value(lcd->reset, 1);
0325     usleep_range(10000, 12000);
0326     gpio_set_value(lcd->reset, 0);
0327     usleep_range(10000, 12000);
0328     gpio_set_value(lcd->reset, 1);
0329 
0330     /* The controller needs 120ms to recover from reset */
0331     msleep(120);
0332 }
0333 
0334 static int hx8357_lcd_init(struct lcd_device *lcdev)
0335 {
0336     struct hx8357_data *lcd = lcd_get_data(lcdev);
0337     int ret;
0338 
0339     /*
0340      * Set the interface selection pins to SPI mode, with three
0341      * wires
0342      */
0343     if (lcd->use_im_pins) {
0344         gpio_set_value_cansleep(lcd->im_pins[0], 1);
0345         gpio_set_value_cansleep(lcd->im_pins[1], 0);
0346         gpio_set_value_cansleep(lcd->im_pins[2], 1);
0347     }
0348 
0349     ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
0350                 ARRAY_SIZE(hx8357_seq_power));
0351     if (ret < 0)
0352         return ret;
0353 
0354     ret = hx8357_spi_write_array(lcdev, hx8357_seq_vcom,
0355                 ARRAY_SIZE(hx8357_seq_vcom));
0356     if (ret < 0)
0357         return ret;
0358 
0359     ret = hx8357_spi_write_array(lcdev, hx8357_seq_power_normal,
0360                 ARRAY_SIZE(hx8357_seq_power_normal));
0361     if (ret < 0)
0362         return ret;
0363 
0364     ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_driving,
0365                 ARRAY_SIZE(hx8357_seq_panel_driving));
0366     if (ret < 0)
0367         return ret;
0368 
0369     ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_frame,
0370                 ARRAY_SIZE(hx8357_seq_display_frame));
0371     if (ret < 0)
0372         return ret;
0373 
0374     ret = hx8357_spi_write_array(lcdev, hx8357_seq_panel_related,
0375                 ARRAY_SIZE(hx8357_seq_panel_related));
0376     if (ret < 0)
0377         return ret;
0378 
0379     ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined1,
0380                 ARRAY_SIZE(hx8357_seq_undefined1));
0381     if (ret < 0)
0382         return ret;
0383 
0384     ret = hx8357_spi_write_array(lcdev, hx8357_seq_undefined2,
0385                 ARRAY_SIZE(hx8357_seq_undefined2));
0386     if (ret < 0)
0387         return ret;
0388 
0389     ret = hx8357_spi_write_array(lcdev, hx8357_seq_gamma,
0390                 ARRAY_SIZE(hx8357_seq_gamma));
0391     if (ret < 0)
0392         return ret;
0393 
0394     ret = hx8357_spi_write_array(lcdev, hx8357_seq_address_mode,
0395                 ARRAY_SIZE(hx8357_seq_address_mode));
0396     if (ret < 0)
0397         return ret;
0398 
0399     ret = hx8357_spi_write_array(lcdev, hx8357_seq_pixel_format,
0400                 ARRAY_SIZE(hx8357_seq_pixel_format));
0401     if (ret < 0)
0402         return ret;
0403 
0404     ret = hx8357_spi_write_array(lcdev, hx8357_seq_column_address,
0405                 ARRAY_SIZE(hx8357_seq_column_address));
0406     if (ret < 0)
0407         return ret;
0408 
0409     ret = hx8357_spi_write_array(lcdev, hx8357_seq_page_address,
0410                 ARRAY_SIZE(hx8357_seq_page_address));
0411     if (ret < 0)
0412         return ret;
0413 
0414     ret = hx8357_spi_write_array(lcdev, hx8357_seq_rgb,
0415                 ARRAY_SIZE(hx8357_seq_rgb));
0416     if (ret < 0)
0417         return ret;
0418 
0419     ret = hx8357_spi_write_array(lcdev, hx8357_seq_display_mode,
0420                 ARRAY_SIZE(hx8357_seq_display_mode));
0421     if (ret < 0)
0422         return ret;
0423 
0424     ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
0425     if (ret < 0)
0426         return ret;
0427 
0428     /*
0429      * The controller needs 120ms to fully recover from exiting sleep mode
0430      */
0431     msleep(120);
0432 
0433     ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
0434     if (ret < 0)
0435         return ret;
0436 
0437     usleep_range(5000, 7000);
0438 
0439     ret = hx8357_spi_write_byte(lcdev, HX8357_WRITE_MEMORY_START);
0440     if (ret < 0)
0441         return ret;
0442 
0443     return 0;
0444 }
0445 
0446 static int hx8369_lcd_init(struct lcd_device *lcdev)
0447 {
0448     int ret;
0449 
0450     ret = hx8357_spi_write_array(lcdev, hx8369_seq_extension_command,
0451                 ARRAY_SIZE(hx8369_seq_extension_command));
0452     if (ret < 0)
0453         return ret;
0454     usleep_range(10000, 12000);
0455 
0456     ret = hx8357_spi_write_array(lcdev, hx8369_seq_display_related,
0457                 ARRAY_SIZE(hx8369_seq_display_related));
0458     if (ret < 0)
0459         return ret;
0460 
0461     ret = hx8357_spi_write_array(lcdev, hx8369_seq_panel_waveform_cycle,
0462                 ARRAY_SIZE(hx8369_seq_panel_waveform_cycle));
0463     if (ret < 0)
0464         return ret;
0465 
0466     ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_address_mode,
0467                 ARRAY_SIZE(hx8369_seq_set_address_mode));
0468     if (ret < 0)
0469         return ret;
0470 
0471     ret = hx8357_spi_write_array(lcdev, hx8369_seq_vcom,
0472                 ARRAY_SIZE(hx8369_seq_vcom));
0473     if (ret < 0)
0474         return ret;
0475 
0476     ret = hx8357_spi_write_array(lcdev, hx8369_seq_gip,
0477                 ARRAY_SIZE(hx8369_seq_gip));
0478     if (ret < 0)
0479         return ret;
0480 
0481     ret = hx8357_spi_write_array(lcdev, hx8369_seq_power,
0482                 ARRAY_SIZE(hx8369_seq_power));
0483     if (ret < 0)
0484         return ret;
0485 
0486     ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
0487     if (ret < 0)
0488         return ret;
0489 
0490     /*
0491      * The controller needs 120ms to fully recover from exiting sleep mode
0492      */
0493     msleep(120);
0494 
0495     ret = hx8357_spi_write_array(lcdev, hx8369_seq_gamma_curve_related,
0496                 ARRAY_SIZE(hx8369_seq_gamma_curve_related));
0497     if (ret < 0)
0498         return ret;
0499 
0500     ret = hx8357_spi_write_byte(lcdev, HX8357_EXIT_SLEEP_MODE);
0501     if (ret < 0)
0502         return ret;
0503     usleep_range(1000, 1200);
0504 
0505     ret = hx8357_spi_write_array(lcdev, hx8369_seq_write_CABC_control,
0506                 ARRAY_SIZE(hx8369_seq_write_CABC_control));
0507     if (ret < 0)
0508         return ret;
0509     usleep_range(10000, 12000);
0510 
0511     ret = hx8357_spi_write_array(lcdev,
0512             hx8369_seq_write_CABC_control_setting,
0513             ARRAY_SIZE(hx8369_seq_write_CABC_control_setting));
0514     if (ret < 0)
0515         return ret;
0516 
0517     ret = hx8357_spi_write_array(lcdev,
0518             hx8369_seq_write_CABC_min_brightness,
0519             ARRAY_SIZE(hx8369_seq_write_CABC_min_brightness));
0520     if (ret < 0)
0521         return ret;
0522     usleep_range(10000, 12000);
0523 
0524     ret = hx8357_spi_write_array(lcdev, hx8369_seq_set_display_brightness,
0525                 ARRAY_SIZE(hx8369_seq_set_display_brightness));
0526     if (ret < 0)
0527         return ret;
0528 
0529     ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
0530     if (ret < 0)
0531         return ret;
0532 
0533     return 0;
0534 }
0535 
0536 #define POWER_IS_ON(pwr)    ((pwr) <= FB_BLANK_NORMAL)
0537 
0538 static int hx8357_set_power(struct lcd_device *lcdev, int power)
0539 {
0540     struct hx8357_data *lcd = lcd_get_data(lcdev);
0541     int ret = 0;
0542 
0543     if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->state))
0544         ret = hx8357_exit_standby(lcdev);
0545     else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->state))
0546         ret = hx8357_enter_standby(lcdev);
0547 
0548     if (ret == 0)
0549         lcd->state = power;
0550     else
0551         dev_warn(&lcdev->dev, "failed to set power mode %d\n", power);
0552 
0553     return ret;
0554 }
0555 
0556 static int hx8357_get_power(struct lcd_device *lcdev)
0557 {
0558     struct hx8357_data *lcd = lcd_get_data(lcdev);
0559 
0560     return lcd->state;
0561 }
0562 
0563 static struct lcd_ops hx8357_ops = {
0564     .set_power  = hx8357_set_power,
0565     .get_power  = hx8357_get_power,
0566 };
0567 
0568 static const struct of_device_id hx8357_dt_ids[] = {
0569     {
0570         .compatible = "himax,hx8357",
0571         .data = hx8357_lcd_init,
0572     },
0573     {
0574         .compatible = "himax,hx8369",
0575         .data = hx8369_lcd_init,
0576     },
0577     {},
0578 };
0579 MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
0580 
0581 static int hx8357_probe(struct spi_device *spi)
0582 {
0583     struct lcd_device *lcdev;
0584     struct hx8357_data *lcd;
0585     const struct of_device_id *match;
0586     int i, ret;
0587 
0588     lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
0589     if (!lcd)
0590         return -ENOMEM;
0591 
0592     ret = spi_setup(spi);
0593     if (ret < 0) {
0594         dev_err(&spi->dev, "SPI setup failed.\n");
0595         return ret;
0596     }
0597 
0598     lcd->spi = spi;
0599 
0600     match = of_match_device(hx8357_dt_ids, &spi->dev);
0601     if (!match || !match->data)
0602         return -EINVAL;
0603 
0604     lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
0605     if (!gpio_is_valid(lcd->reset)) {
0606         dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
0607         return -EINVAL;
0608     }
0609 
0610     ret = devm_gpio_request_one(&spi->dev, lcd->reset,
0611                     GPIOF_OUT_INIT_HIGH,
0612                     "hx8357-reset");
0613     if (ret) {
0614         dev_err(&spi->dev,
0615             "failed to request gpio %d: %d\n",
0616             lcd->reset, ret);
0617         return -EINVAL;
0618     }
0619 
0620     if (of_find_property(spi->dev.of_node, "im-gpios", NULL)) {
0621         lcd->use_im_pins = 1;
0622 
0623         for (i = 0; i < HX8357_NUM_IM_PINS; i++) {
0624             lcd->im_pins[i] = of_get_named_gpio(spi->dev.of_node,
0625                                 "im-gpios", i);
0626             if (lcd->im_pins[i] == -EPROBE_DEFER) {
0627                 dev_info(&spi->dev, "GPIO requested is not here yet, deferring the probe\n");
0628                 return -EPROBE_DEFER;
0629             }
0630             if (!gpio_is_valid(lcd->im_pins[i])) {
0631                 dev_err(&spi->dev, "Missing dt property: im-gpios\n");
0632                 return -EINVAL;
0633             }
0634 
0635             ret = devm_gpio_request_one(&spi->dev, lcd->im_pins[i],
0636                             GPIOF_OUT_INIT_LOW,
0637                             "im_pins");
0638             if (ret) {
0639                 dev_err(&spi->dev, "failed to request gpio %d: %d\n",
0640                     lcd->im_pins[i], ret);
0641                 return -EINVAL;
0642             }
0643         }
0644     } else {
0645         lcd->use_im_pins = 0;
0646     }
0647 
0648     lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
0649                     &hx8357_ops);
0650     if (IS_ERR(lcdev)) {
0651         ret = PTR_ERR(lcdev);
0652         return ret;
0653     }
0654     spi_set_drvdata(spi, lcdev);
0655 
0656     hx8357_lcd_reset(lcdev);
0657 
0658     ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
0659     if (ret) {
0660         dev_err(&spi->dev, "Couldn't initialize panel\n");
0661         return ret;
0662     }
0663 
0664     dev_info(&spi->dev, "Panel probed\n");
0665 
0666     return 0;
0667 }
0668 
0669 static struct spi_driver hx8357_driver = {
0670     .probe  = hx8357_probe,
0671     .driver = {
0672         .name = "hx8357",
0673         .of_match_table = hx8357_dt_ids,
0674     },
0675 };
0676 
0677 module_spi_driver(hx8357_driver);
0678 
0679 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
0680 MODULE_DESCRIPTION("Himax HX-8357 LCD Driver");
0681 MODULE_LICENSE("GPL");