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