cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

hx8357.c (16766B)


      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");