blob: 23f50b92a930b25f80986a529f2bad3fb5d6c877 [file] [log] [blame]
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -08001/*
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
Alexandre Bellonifb525662013-08-01 10:40:37 +020074#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
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -080086struct hx8357_data {
87 unsigned im_pins[HX8357_NUM_IM_PINS];
88 unsigned reset;
89 struct spi_device *spi;
90 int state;
Maxime Ripardccf99012013-08-01 10:40:36 +020091 bool use_im_pins;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -080092};
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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200159static 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
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800214static 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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200290 /*
291 * The controller needs 120ms when entering in sleep mode before we can
292 * send the command to go off sleep mode
293 */
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800294 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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200307 /*
308 * The controller needs 120ms when exiting from sleep mode before we
309 * can send the command to enter in sleep mode
310 */
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800311 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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200320static 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
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800335static 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 */
Maxime Ripardccf99012013-08-01 10:40:36 +0200344 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 }
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800349
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800350 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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200429 /*
430 * The controller needs 120ms to fully recover from exiting sleep mode
431 */
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800432 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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200447static 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
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800537#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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200569static 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
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800582static int hx8357_probe(struct spi_device *spi)
583{
584 struct lcd_device *lcdev;
585 struct hx8357_data *lcd;
Alexandre Bellonifb525662013-08-01 10:40:37 +0200586 const struct of_device_id *match;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800587 int i, ret;
588
589 lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
Jingoo Hanaff70f92014-04-03 14:49:00 -0700590 if (!lcd)
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800591 return -ENOMEM;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800592
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
Alexandre Bellonifb525662013-08-01 10:40:37 +0200601 match = of_match_device(hx8357_dt_ids, &spi->dev);
602 if (!match || !match->data)
603 return -EINVAL;
604
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800605 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
Maxime Ripardccf99012013-08-01 10:40:36 +0200621 if (of_find_property(spi->dev.of_node, "im-gpios", NULL)) {
622 lcd->use_im_pins = 1;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800623
Maxime Ripardccf99012013-08-01 10:40:36 +0200624 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 }
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800644 }
Maxime Ripardccf99012013-08-01 10:40:36 +0200645 } else {
646 lcd->use_im_pins = 0;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800647 }
648
Jingoo Hanea5092c2013-11-12 15:09:25 -0800649 lcdev = devm_lcd_device_register(&spi->dev, "mxsfb", &spi->dev, lcd,
650 &hx8357_ops);
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800651 if (IS_ERR(lcdev)) {
652 ret = PTR_ERR(lcdev);
653 return ret;
654 }
655 spi_set_drvdata(spi, lcdev);
656
Alexandre Bellonifb525662013-08-01 10:40:37 +0200657 hx8357_lcd_reset(lcdev);
658
659 ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800660 if (ret) {
661 dev_err(&spi->dev, "Couldn't initialize panel\n");
Jingoo Hanea5092c2013-11-12 15:09:25 -0800662 return ret;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800663 }
664
665 dev_info(&spi->dev, "Panel probed\n");
666
667 return 0;
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800668}
669
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800670static struct spi_driver hx8357_driver = {
671 .probe = hx8357_probe,
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800672 .driver = {
673 .name = "hx8357",
Sachin Kamatc962f7b2013-11-12 15:09:47 -0800674 .of_match_table = hx8357_dt_ids,
Maxime Ripard8a6c1dd2013-02-21 16:43:56 -0800675 },
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");