1 // SPDX-License-Identifier: GPL-2.0
3 * Sony ACX565AKM LCD Panel driver
5 * Copyright (C) 2019 Texas Instruments Incorporated
7 * Based on the omapdrm-specific panel-sony-acx565akm driver
9 * Copyright (C) 2010 Nokia Corporation
10 * Author: Imre Deak <imre.deak@nokia.com>
14 * TODO (to be addressed with hardware access to test the changes):
16 * - Update backlight support to use backlight_update_status() etc.
17 * - Use prepare/unprepare for the basic power on/off of the backligt
20 #include <linux/backlight.h>
21 #include <linux/delay.h>
22 #include <linux/gpio/consumer.h>
23 #include <linux/jiffies.h>
24 #include <linux/module.h>
25 #include <linux/mutex.h>
26 #include <linux/sched.h>
27 #include <linux/spi/spi.h>
28 #include <video/mipi_display.h>
30 #include <drm/drm_connector.h>
31 #include <drm/drm_modes.h>
32 #include <drm/drm_panel.h>
34 #define CTRL_DISP_BRIGHTNESS_CTRL_ON BIT(5)
35 #define CTRL_DISP_AMBIENT_LIGHT_CTRL_ON BIT(4)
36 #define CTRL_DISP_BACKLIGHT_ON BIT(2)
37 #define CTRL_DISP_AUTO_BRIGHTNESS_ON BIT(1)
39 #define MIPID_CMD_WRITE_CABC 0x55
40 #define MIPID_CMD_READ_CABC 0x56
42 #define MIPID_VER_LPH8923 3
43 #define MIPID_VER_LS041Y3 4
44 #define MIPID_VER_L4F00311 8
45 #define MIPID_VER_ACX565AKM 9
47 struct acx565akm_panel
{
48 struct drm_panel panel
;
50 struct spi_device
*spi
;
51 struct gpio_desc
*reset_gpio
;
52 struct backlight_device
*backlight
;
64 unsigned int cabc_mode
;
66 * Next value of jiffies when we can issue the next sleep in/out
69 unsigned long hw_guard_end
;
70 unsigned long hw_guard_wait
; /* max guard time in jiffies */
73 #define to_acx565akm_device(p) container_of(p, struct acx565akm_panel, panel)
75 static void acx565akm_transfer(struct acx565akm_panel
*lcd
, int cmd
,
76 const u8
*wbuf
, int wlen
, u8
*rbuf
, int rlen
)
79 struct spi_transfer
*x
, xfer
[5];
84 memset(xfer
, 0, sizeof(xfer
));
92 if (rlen
> 1 && wlen
== 0) {
94 * Between the command and the response data there is a
95 * dummy clock cycle. Add an extra bit after the command
96 * word to account for this.
98 x
->bits_per_word
= 10;
101 spi_message_add_tail(x
, &m
);
107 x
->bits_per_word
= 9;
108 spi_message_add_tail(x
, &m
);
115 spi_message_add_tail(x
, &m
);
118 ret
= spi_sync(lcd
->spi
, &m
);
120 dev_dbg(&lcd
->spi
->dev
, "spi_sync %d\n", ret
);
123 static inline void acx565akm_cmd(struct acx565akm_panel
*lcd
, int cmd
)
125 acx565akm_transfer(lcd
, cmd
, NULL
, 0, NULL
, 0);
128 static inline void acx565akm_write(struct acx565akm_panel
*lcd
,
129 int reg
, const u8
*buf
, int len
)
131 acx565akm_transfer(lcd
, reg
, buf
, len
, NULL
, 0);
134 static inline void acx565akm_read(struct acx565akm_panel
*lcd
,
135 int reg
, u8
*buf
, int len
)
137 acx565akm_transfer(lcd
, reg
, NULL
, 0, buf
, len
);
140 /* -----------------------------------------------------------------------------
141 * Auto Brightness Control Via sysfs
144 static unsigned int acx565akm_get_cabc_mode(struct acx565akm_panel
*lcd
)
146 return lcd
->cabc_mode
;
149 static void acx565akm_set_cabc_mode(struct acx565akm_panel
*lcd
,
154 lcd
->cabc_mode
= mode
;
158 acx565akm_read(lcd
, MIPID_CMD_READ_CABC
, (u8
*)&cabc_ctrl
, 1);
160 cabc_ctrl
|= (1 << 8) | (mode
& 3);
161 acx565akm_write(lcd
, MIPID_CMD_WRITE_CABC
, (u8
*)&cabc_ctrl
, 2);
164 static unsigned int acx565akm_get_hw_cabc_mode(struct acx565akm_panel
*lcd
)
168 acx565akm_read(lcd
, MIPID_CMD_READ_CABC
, &cabc_ctrl
, 1);
169 return cabc_ctrl
& 3;
172 static const char * const acx565akm_cabc_modes
[] = {
173 "off", /* always used when CABC is not supported */
179 static ssize_t
cabc_mode_show(struct device
*dev
,
180 struct device_attribute
*attr
,
183 struct acx565akm_panel
*lcd
= dev_get_drvdata(dev
);
184 const char *mode_str
;
190 mode
= acx565akm_get_cabc_mode(lcd
);
192 mode_str
= "unknown";
193 if (mode
>= 0 && mode
< ARRAY_SIZE(acx565akm_cabc_modes
))
194 mode_str
= acx565akm_cabc_modes
[mode
];
196 return sprintf(buf
, "%s\n", mode_str
);
199 static ssize_t
cabc_mode_store(struct device
*dev
,
200 struct device_attribute
*attr
,
201 const char *buf
, size_t count
)
203 struct acx565akm_panel
*lcd
= dev_get_drvdata(dev
);
206 for (i
= 0; i
< ARRAY_SIZE(acx565akm_cabc_modes
); i
++) {
207 const char *mode_str
= acx565akm_cabc_modes
[i
];
208 int cmp_len
= strlen(mode_str
);
210 if (count
> 0 && buf
[count
- 1] == '\n')
212 if (count
!= cmp_len
)
215 if (strncmp(buf
, mode_str
, cmp_len
) == 0)
219 if (i
== ARRAY_SIZE(acx565akm_cabc_modes
))
222 if (!lcd
->has_cabc
&& i
!= 0)
225 mutex_lock(&lcd
->mutex
);
226 acx565akm_set_cabc_mode(lcd
, i
);
227 mutex_unlock(&lcd
->mutex
);
232 static ssize_t
cabc_available_modes_show(struct device
*dev
,
233 struct device_attribute
*attr
,
236 struct acx565akm_panel
*lcd
= dev_get_drvdata(dev
);
241 return sprintf(buf
, "%s\n", acx565akm_cabc_modes
[0]);
243 for (i
= 0; i
< ARRAY_SIZE(acx565akm_cabc_modes
); i
++)
244 len
+= sprintf(&buf
[len
], "%s%s", i
? " " : "",
245 acx565akm_cabc_modes
[i
]);
252 static DEVICE_ATTR_RW(cabc_mode
);
253 static DEVICE_ATTR_RO(cabc_available_modes
);
255 static struct attribute
*acx565akm_cabc_attrs
[] = {
256 &dev_attr_cabc_mode
.attr
,
257 &dev_attr_cabc_available_modes
.attr
,
261 static const struct attribute_group acx565akm_cabc_attr_group
= {
262 .attrs
= acx565akm_cabc_attrs
,
265 /* -----------------------------------------------------------------------------
269 static int acx565akm_get_actual_brightness(struct acx565akm_panel
*lcd
)
273 acx565akm_read(lcd
, MIPI_DCS_GET_DISPLAY_BRIGHTNESS
, &bv
, 1);
278 static void acx565akm_set_brightness(struct acx565akm_panel
*lcd
, int level
)
283 bv
= level
| (1 << 8);
284 acx565akm_write(lcd
, MIPI_DCS_SET_DISPLAY_BRIGHTNESS
, (u8
*)&bv
, 2);
286 acx565akm_read(lcd
, MIPI_DCS_GET_CONTROL_DISPLAY
, (u8
*)&ctrl
, 1);
288 ctrl
|= CTRL_DISP_BRIGHTNESS_CTRL_ON
|
289 CTRL_DISP_BACKLIGHT_ON
;
291 ctrl
&= ~(CTRL_DISP_BRIGHTNESS_CTRL_ON
|
292 CTRL_DISP_BACKLIGHT_ON
);
295 acx565akm_write(lcd
, MIPI_DCS_WRITE_CONTROL_DISPLAY
, (u8
*)&ctrl
, 2);
298 static int acx565akm_bl_update_status_locked(struct backlight_device
*dev
)
300 struct acx565akm_panel
*lcd
= dev_get_drvdata(&dev
->dev
);
303 if (dev
->props
.fb_blank
== FB_BLANK_UNBLANK
&&
304 dev
->props
.power
== FB_BLANK_UNBLANK
)
305 level
= dev
->props
.brightness
;
309 acx565akm_set_brightness(lcd
, level
);
314 static int acx565akm_bl_update_status(struct backlight_device
*dev
)
316 struct acx565akm_panel
*lcd
= dev_get_drvdata(&dev
->dev
);
319 mutex_lock(&lcd
->mutex
);
320 ret
= acx565akm_bl_update_status_locked(dev
);
321 mutex_unlock(&lcd
->mutex
);
326 static int acx565akm_bl_get_intensity(struct backlight_device
*dev
)
328 struct acx565akm_panel
*lcd
= dev_get_drvdata(&dev
->dev
);
329 unsigned int intensity
;
331 mutex_lock(&lcd
->mutex
);
333 if (dev
->props
.fb_blank
== FB_BLANK_UNBLANK
&&
334 dev
->props
.power
== FB_BLANK_UNBLANK
)
335 intensity
= acx565akm_get_actual_brightness(lcd
);
339 mutex_unlock(&lcd
->mutex
);
344 static const struct backlight_ops acx565akm_bl_ops
= {
345 .get_brightness
= acx565akm_bl_get_intensity
,
346 .update_status
= acx565akm_bl_update_status
,
349 static int acx565akm_backlight_init(struct acx565akm_panel
*lcd
)
351 struct backlight_properties props
= {
352 .fb_blank
= FB_BLANK_UNBLANK
,
353 .power
= FB_BLANK_UNBLANK
,
354 .type
= BACKLIGHT_RAW
,
358 lcd
->backlight
= backlight_device_register(lcd
->name
, &lcd
->spi
->dev
,
359 lcd
, &acx565akm_bl_ops
,
361 if (IS_ERR(lcd
->backlight
)) {
362 ret
= PTR_ERR(lcd
->backlight
);
363 lcd
->backlight
= NULL
;
368 ret
= sysfs_create_group(&lcd
->backlight
->dev
.kobj
,
369 &acx565akm_cabc_attr_group
);
371 dev_err(&lcd
->spi
->dev
,
372 "%s failed to create sysfs files\n", __func__
);
373 backlight_device_unregister(lcd
->backlight
);
377 lcd
->cabc_mode
= acx565akm_get_hw_cabc_mode(lcd
);
380 lcd
->backlight
->props
.max_brightness
= 255;
381 lcd
->backlight
->props
.brightness
= acx565akm_get_actual_brightness(lcd
);
383 acx565akm_bl_update_status_locked(lcd
->backlight
);
388 static void acx565akm_backlight_cleanup(struct acx565akm_panel
*lcd
)
391 sysfs_remove_group(&lcd
->backlight
->dev
.kobj
,
392 &acx565akm_cabc_attr_group
);
394 backlight_device_unregister(lcd
->backlight
);
397 /* -----------------------------------------------------------------------------
398 * DRM Bridge Operations
401 static void acx565akm_set_sleep_mode(struct acx565akm_panel
*lcd
, int on
)
403 int cmd
= on
? MIPI_DCS_ENTER_SLEEP_MODE
: MIPI_DCS_EXIT_SLEEP_MODE
;
407 * We have to keep 120msec between sleep in/out commands.
410 wait
= lcd
->hw_guard_end
- jiffies
;
411 if ((long)wait
> 0 && wait
<= lcd
->hw_guard_wait
) {
412 set_current_state(TASK_UNINTERRUPTIBLE
);
413 schedule_timeout(wait
);
416 acx565akm_cmd(lcd
, cmd
);
418 lcd
->hw_guard_wait
= msecs_to_jiffies(120);
419 lcd
->hw_guard_end
= jiffies
+ lcd
->hw_guard_wait
;
422 static void acx565akm_set_display_state(struct acx565akm_panel
*lcd
,
425 int cmd
= enabled
? MIPI_DCS_SET_DISPLAY_ON
: MIPI_DCS_SET_DISPLAY_OFF
;
427 acx565akm_cmd(lcd
, cmd
);
430 static int acx565akm_power_on(struct acx565akm_panel
*lcd
)
435 gpiod_set_value(lcd
->reset_gpio
, 1);
438 dev_dbg(&lcd
->spi
->dev
, "panel already enabled\n");
443 * We have to meet all the following delay requirements:
444 * 1. tRW: reset pulse width 10usec (7.12.1)
445 * 2. tRT: reset cancel time 5msec (7.12.1)
446 * 3. Providing PCLK,HS,VS signals for 2 frames = ~50msec worst
448 * 4. 120msec before the sleep out command (7.12.1)
452 acx565akm_set_sleep_mode(lcd
, 0);
455 /* 5msec between sleep out and the next command. (8.2.16) */
456 usleep_range(5000, 10000);
457 acx565akm_set_display_state(lcd
, 1);
458 acx565akm_set_cabc_mode(lcd
, lcd
->cabc_mode
);
460 return acx565akm_bl_update_status_locked(lcd
->backlight
);
463 static void acx565akm_power_off(struct acx565akm_panel
*lcd
)
468 acx565akm_set_display_state(lcd
, 0);
469 acx565akm_set_sleep_mode(lcd
, 1);
470 lcd
->enabled
= false;
472 * We have to provide PCLK,HS,VS signals for 2 frames (worst case
473 * ~50msec) after sending the sleep in command and asserting the
474 * reset signal. We probably could assert the reset w/o the delay
475 * but we still delay to avoid possible artifacts. (7.6.1)
479 gpiod_set_value(lcd
->reset_gpio
, 0);
481 /* FIXME need to tweak this delay */
485 static int acx565akm_disable(struct drm_panel
*panel
)
487 struct acx565akm_panel
*lcd
= to_acx565akm_device(panel
);
489 mutex_lock(&lcd
->mutex
);
490 acx565akm_power_off(lcd
);
491 mutex_unlock(&lcd
->mutex
);
496 static int acx565akm_enable(struct drm_panel
*panel
)
498 struct acx565akm_panel
*lcd
= to_acx565akm_device(panel
);
500 mutex_lock(&lcd
->mutex
);
501 acx565akm_power_on(lcd
);
502 mutex_unlock(&lcd
->mutex
);
507 static const struct drm_display_mode acx565akm_mode
= {
510 .hsync_start
= 800 + 28,
511 .hsync_end
= 800 + 28 + 4,
512 .htotal
= 800 + 28 + 4 + 24,
514 .vsync_start
= 480 + 3,
515 .vsync_end
= 480 + 3 + 3,
516 .vtotal
= 480 + 3 + 3 + 4,
517 .type
= DRM_MODE_TYPE_DRIVER
| DRM_MODE_TYPE_PREFERRED
,
518 .flags
= DRM_MODE_FLAG_NHSYNC
| DRM_MODE_FLAG_NVSYNC
,
523 static int acx565akm_get_modes(struct drm_panel
*panel
,
524 struct drm_connector
*connector
)
526 struct drm_display_mode
*mode
;
528 mode
= drm_mode_duplicate(connector
->dev
, &acx565akm_mode
);
532 drm_mode_set_name(mode
);
533 drm_mode_probed_add(connector
, mode
);
535 connector
->display_info
.width_mm
= acx565akm_mode
.width_mm
;
536 connector
->display_info
.height_mm
= acx565akm_mode
.height_mm
;
537 connector
->display_info
.bus_flags
= DRM_BUS_FLAG_DE_HIGH
538 | DRM_BUS_FLAG_SYNC_SAMPLE_POSEDGE
539 | DRM_BUS_FLAG_PIXDATA_SAMPLE_NEGEDGE
;
544 static const struct drm_panel_funcs acx565akm_funcs
= {
545 .disable
= acx565akm_disable
,
546 .enable
= acx565akm_enable
,
547 .get_modes
= acx565akm_get_modes
,
550 /* -----------------------------------------------------------------------------
551 * Probe, Detect and Remove
554 static int acx565akm_detect(struct acx565akm_panel
*lcd
)
561 * After being taken out of reset the panel needs 5ms before the first
562 * command can be sent.
564 gpiod_set_value(lcd
->reset_gpio
, 1);
565 usleep_range(5000, 10000);
567 acx565akm_read(lcd
, MIPI_DCS_GET_DISPLAY_STATUS
, (u8
*)&value
, 4);
568 status
= __be32_to_cpu(value
);
569 lcd
->enabled
= (status
& (1 << 17)) && (status
& (1 << 10));
571 dev_dbg(&lcd
->spi
->dev
,
572 "LCD panel %s by bootloader (status 0x%04x)\n",
573 lcd
->enabled
? "enabled" : "disabled ", status
);
575 acx565akm_read(lcd
, MIPI_DCS_GET_DISPLAY_ID
, lcd
->display_id
, 3);
576 dev_dbg(&lcd
->spi
->dev
, "MIPI display ID: %02x%02x%02x\n",
577 lcd
->display_id
[0], lcd
->display_id
[1], lcd
->display_id
[2]);
579 switch (lcd
->display_id
[0]) {
581 lcd
->model
= MIPID_VER_ACX565AKM
;
582 lcd
->name
= "acx565akm";
587 lcd
->model
= MIPID_VER_L4F00311
;
588 lcd
->name
= "l4f00311";
591 lcd
->model
= MIPID_VER_LPH8923
;
592 lcd
->name
= "lph8923";
595 lcd
->model
= MIPID_VER_LS041Y3
;
596 lcd
->name
= "ls041y3";
599 lcd
->name
= "unknown";
600 dev_err(&lcd
->spi
->dev
, "unknown display ID\n");
605 lcd
->revision
= lcd
->display_id
[1];
607 dev_info(&lcd
->spi
->dev
, "%s rev %02x panel detected\n",
608 lcd
->name
, lcd
->revision
);
612 gpiod_set_value(lcd
->reset_gpio
, 0);
617 static int acx565akm_probe(struct spi_device
*spi
)
619 struct acx565akm_panel
*lcd
;
622 lcd
= devm_kzalloc(&spi
->dev
, sizeof(*lcd
), GFP_KERNEL
);
626 spi_set_drvdata(spi
, lcd
);
627 spi
->mode
= SPI_MODE_3
;
630 mutex_init(&lcd
->mutex
);
632 lcd
->reset_gpio
= devm_gpiod_get(&spi
->dev
, "reset", GPIOD_OUT_HIGH
);
633 if (IS_ERR(lcd
->reset_gpio
)) {
634 dev_err(&spi
->dev
, "failed to get reset GPIO\n");
635 return PTR_ERR(lcd
->reset_gpio
);
638 ret
= acx565akm_detect(lcd
);
640 dev_err(&spi
->dev
, "panel detection failed\n");
645 ret
= acx565akm_backlight_init(lcd
);
650 drm_panel_init(&lcd
->panel
, &lcd
->spi
->dev
, &acx565akm_funcs
,
651 DRM_MODE_CONNECTOR_DPI
);
653 drm_panel_add(&lcd
->panel
);
658 static int acx565akm_remove(struct spi_device
*spi
)
660 struct acx565akm_panel
*lcd
= spi_get_drvdata(spi
);
662 drm_panel_remove(&lcd
->panel
);
665 acx565akm_backlight_cleanup(lcd
);
667 drm_panel_disable(&lcd
->panel
);
668 drm_panel_unprepare(&lcd
->panel
);
673 static const struct of_device_id acx565akm_of_match
[] = {
674 { .compatible
= "sony,acx565akm", },
678 MODULE_DEVICE_TABLE(of
, acx565akm_of_match
);
680 static const struct spi_device_id acx565akm_ids
[] = {
685 MODULE_DEVICE_TABLE(spi
, acx565akm_ids
);
687 static struct spi_driver acx565akm_driver
= {
688 .probe
= acx565akm_probe
,
689 .remove
= acx565akm_remove
,
690 .id_table
= acx565akm_ids
,
692 .name
= "panel-sony-acx565akm",
693 .of_match_table
= acx565akm_of_match
,
697 module_spi_driver(acx565akm_driver
);
699 MODULE_AUTHOR("Nokia Corporation");
700 MODULE_DESCRIPTION("Sony ACX565AKM LCD Panel Driver");
701 MODULE_LICENSE("GPL");