aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video
diff options
context:
space:
mode:
authorAlexandre Belloni <alexandre.belloni@free-electrons.com>2013-08-01 04:40:37 -0400
committerTomi Valkeinen <tomi.valkeinen@ti.com>2013-08-02 06:15:08 -0400
commitfb52566873ca8c7006948b9d51c7f3fbcc0b1116 (patch)
treea0cebd0e95a39fbefcfb23f936ee72c8eb4893bc /drivers/video
parentccf9901ffec4b41a3a5c22580c4a7d358d88ca9f (diff)
fb: backlight: HX8357: Add HX8369 support
Add support for the Himax HX8369 controller as it is quite similar to the hx8357. Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com> Acked-by: Jingoo Han <jg1.han@samsung.com> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ti.com>
Diffstat (limited to 'drivers/video')
-rw-r--r--drivers/video/backlight/hx8357.c219
1 files changed, 204 insertions, 15 deletions
diff --git a/drivers/video/backlight/hx8357.c b/drivers/video/backlight/hx8357.c
index 47237fa73b0c..c7af8c45ab8a 100644
--- a/drivers/video/backlight/hx8357.c
+++ b/drivers/video/backlight/hx8357.c
@@ -71,6 +71,18 @@
71#define HX8357_SET_POWER_NORMAL 0xd2 71#define HX8357_SET_POWER_NORMAL 0xd2
72#define HX8357_SET_PANEL_RELATED 0xe9 72#define HX8357_SET_PANEL_RELATED 0xe9
73 73
74#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
74struct hx8357_data { 86struct hx8357_data {
75 unsigned im_pins[HX8357_NUM_IM_PINS]; 87 unsigned im_pins[HX8357_NUM_IM_PINS];
76 unsigned reset; 88 unsigned reset;
@@ -144,6 +156,61 @@ static u8 hx8357_seq_display_mode[] = {
144 HX8357_SET_DISPLAY_MODE_RGB_INTERFACE, 156 HX8357_SET_DISPLAY_MODE_RGB_INTERFACE,
145}; 157};
146 158
159static 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
147static int hx8357_spi_write_then_read(struct lcd_device *lcdev, 214static int hx8357_spi_write_then_read(struct lcd_device *lcdev,
148 u8 *txbuf, u16 txlen, 215 u8 *txbuf, u16 txlen,
149 u8 *rxbuf, u16 rxlen) 216 u8 *rxbuf, u16 rxlen)
@@ -220,6 +287,10 @@ static int hx8357_enter_standby(struct lcd_device *lcdev)
220 if (ret < 0) 287 if (ret < 0)
221 return ret; 288 return ret;
222 289
290 /*
291 * The controller needs 120ms when entering in sleep mode before we can
292 * send the command to go off sleep mode
293 */
223 msleep(120); 294 msleep(120);
224 295
225 return 0; 296 return 0;
@@ -233,6 +304,10 @@ static int hx8357_exit_standby(struct lcd_device *lcdev)
233 if (ret < 0) 304 if (ret < 0)
234 return ret; 305 return ret;
235 306
307 /*
308 * The controller needs 120ms when exiting from sleep mode before we
309 * can send the command to enter in sleep mode
310 */
236 msleep(120); 311 msleep(120);
237 312
238 ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); 313 ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
@@ -242,6 +317,21 @@ static int hx8357_exit_standby(struct lcd_device *lcdev)
242 return 0; 317 return 0;
243} 318}
244 319
320static 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
245static int hx8357_lcd_init(struct lcd_device *lcdev) 335static int hx8357_lcd_init(struct lcd_device *lcdev)
246{ 336{
247 struct hx8357_data *lcd = lcd_get_data(lcdev); 337 struct hx8357_data *lcd = lcd_get_data(lcdev);
@@ -257,14 +347,6 @@ static int hx8357_lcd_init(struct lcd_device *lcdev)
257 gpio_set_value_cansleep(lcd->im_pins[2], 1); 347 gpio_set_value_cansleep(lcd->im_pins[2], 1);
258 } 348 }
259 349
260 /* Reset the screen */
261 gpio_set_value(lcd->reset, 1);
262 usleep_range(10000, 12000);
263 gpio_set_value(lcd->reset, 0);
264 usleep_range(10000, 12000);
265 gpio_set_value(lcd->reset, 1);
266 msleep(120);
267
268 ret = hx8357_spi_write_array(lcdev, hx8357_seq_power, 350 ret = hx8357_spi_write_array(lcdev, hx8357_seq_power,
269 ARRAY_SIZE(hx8357_seq_power)); 351 ARRAY_SIZE(hx8357_seq_power));
270 if (ret < 0) 352 if (ret < 0)
@@ -344,6 +426,9 @@ static int hx8357_lcd_init(struct lcd_device *lcdev)
344 if (ret < 0) 426 if (ret < 0)
345 return ret; 427 return ret;
346 428
429 /*
430 * The controller needs 120ms to fully recover from exiting sleep mode
431 */
347 msleep(120); 432 msleep(120);
348 433
349 ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON); 434 ret = hx8357_spi_write_byte(lcdev, HX8357_SET_DISPLAY_ON);
@@ -359,6 +444,96 @@ static int hx8357_lcd_init(struct lcd_device *lcdev)
359 return 0; 444 return 0;
360} 445}
361 446
447static 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
362#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) 537#define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL)
363 538
364static int hx8357_set_power(struct lcd_device *lcdev, int power) 539static int hx8357_set_power(struct lcd_device *lcdev, int power)
@@ -391,10 +566,24 @@ static struct lcd_ops hx8357_ops = {
391 .get_power = hx8357_get_power, 566 .get_power = hx8357_get_power,
392}; 567};
393 568
569static 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
394static int hx8357_probe(struct spi_device *spi) 582static int hx8357_probe(struct spi_device *spi)
395{ 583{
396 struct lcd_device *lcdev; 584 struct lcd_device *lcdev;
397 struct hx8357_data *lcd; 585 struct hx8357_data *lcd;
586 const struct of_device_id *match;
398 int i, ret; 587 int i, ret;
399 588
400 lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL); 589 lcd = devm_kzalloc(&spi->dev, sizeof(*lcd), GFP_KERNEL);
@@ -411,6 +600,10 @@ static int hx8357_probe(struct spi_device *spi)
411 600
412 lcd->spi = spi; 601 lcd->spi = spi;
413 602
603 match = of_match_device(hx8357_dt_ids, &spi->dev);
604 if (!match || !match->data)
605 return -EINVAL;
606
414 lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0); 607 lcd->reset = of_get_named_gpio(spi->dev.of_node, "gpios-reset", 0);
415 if (!gpio_is_valid(lcd->reset)) { 608 if (!gpio_is_valid(lcd->reset)) {
416 dev_err(&spi->dev, "Missing dt property: gpios-reset\n"); 609 dev_err(&spi->dev, "Missing dt property: gpios-reset\n");
@@ -462,7 +655,9 @@ static int hx8357_probe(struct spi_device *spi)
462 } 655 }
463 spi_set_drvdata(spi, lcdev); 656 spi_set_drvdata(spi, lcdev);
464 657
465 ret = hx8357_lcd_init(lcdev); 658 hx8357_lcd_reset(lcdev);
659
660 ret = ((int (*)(struct lcd_device *))match->data)(lcdev);
466 if (ret) { 661 if (ret) {
467 dev_err(&spi->dev, "Couldn't initialize panel\n"); 662 dev_err(&spi->dev, "Couldn't initialize panel\n");
468 goto init_error; 663 goto init_error;
@@ -485,12 +680,6 @@ static int hx8357_remove(struct spi_device *spi)
485 return 0; 680 return 0;
486} 681}
487 682
488static const struct of_device_id hx8357_dt_ids[] = {
489 { .compatible = "himax,hx8357" },
490 {},
491};
492MODULE_DEVICE_TABLE(of, hx8357_dt_ids);
493
494static struct spi_driver hx8357_driver = { 683static struct spi_driver hx8357_driver = {
495 .probe = hx8357_probe, 684 .probe = hx8357_probe,
496 .remove = hx8357_remove, 685 .remove = hx8357_remove,