Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

drm/panel: add backlight support to ea8061v-ams497ee01 driver #200

Draft
wants to merge 1 commit into
base: msm8916/6.5-rc5
Choose a base branch
from

Conversation

Grimler91
Copy link

After looking at the s6e3fa2 driver I have something that is not super ugly and mostly work. Compared to previous WIP it now becomes quite dark at low brightness, and it remembers the brightness when turning off and on the screen.

The panel becomes out of sync quite a lot when changing brightness. I can try playing with sleep times and other things to improve the situation.
I also think (might be my imagination) that the screen becomes a bit green-ish at intermediate brightness levels. Perhaps because some things have been simplified compared to downstream, mainly:

  • Gamma table is dumped from downstream kernel rather than calculated dynamically
  • We do no temperature correction. This should mainly be important for panel function at low temperatures I think though.
  • ACL (automatic current limit(?)) is set to always off rather than on below some brightness threshold

Another issue (which was a problem before my updates here as well) is that the screen can become sluggish after the device comes out of sleep. If I have left the device with screen off for X minutes I sometimes have to do slow movements/touch the screen for several seconds for the touchscreen to react, so inputting the pin-code takes quite some time. After unlocking the screen usually becomes responsive again after a short time.


There is still room for improvement in the driver as well:

  • The magic numbers (0xb2, 0xb6 and so on) should be defined close to the top, as in s6e3fa2 driver
  • A few commands more can be put in more descriptive functions instead (like dsi_dcs_write_seq(dsi, 0xb5, 0x29); -> ea8061v_ams497ee01_acl_opr_on(ctx);)
  • Go through comments and error messages
  • Other things?

Ping @minlexx as well since we discussed these panel drivers before, and you have the a5ulte.

@Grimler91
Copy link
Author

Oh yeah, and if someone wants to try it, remember that the device package has to be updated after building the kernel modules, or this commit reverted.

@stephan-gh
Copy link
Member

Oh yeah, and if someone wants to try it, remember that the device package has to be updated after building the kernel modules, or this commit reverted.

The kernel module does not become part of the device package, the device package just says which kernel modules should be included in the initramfs. AFAICT you did not change the module name so it should still work fine with those changes in the device package?

@Grimler91
Copy link
Author

the device package just says which kernel modules should be included in the initramfs. AFAICT you did not change the module name so it should still work fine with those changes in the device package?

Right, re-building initramfs should be enough. I spent some time when I started looking at this figuring out why my changes did not have an effect when I built linux-postmarketos-qcom-msm8916 or pushed the updated module to /lib/firmware, so just want to save other noobs people like me that trouble.. :)

@minlexx
Copy link

minlexx commented Jun 14, 2021

the screen can become sluggish after the device comes out of sleep

This sounds like a general issue with sleep, not with panel driver.

@Grimler91 Grimler91 force-pushed the msm8916-a5lte-backlight branch 2 times, most recently from fea4a06 to 54d11ea Compare June 15, 2021 07:50
@stephan-gh stephan-gh changed the base branch from master to backup/5.13-rc5/please-rebase June 15, 2021 10:51
@Grimler91 Grimler91 changed the base branch from backup/5.13-rc5/please-rebase to master July 13, 2021 07:14
@minlexx
Copy link

minlexx commented Jul 26, 2021

recently I've tried to debug brightness on a5lte, using patches from latest commit in this branch: https://gitlab.com/minlexx/pmaports/-/commits/a5lte-debug . "Reduce dmesg spam" one helps to get a less spammy dmesg output, and 2nd one - uncommented (+slightly fixed) cmd dumper in mdss_dsi_panel_cmds_send allows us to see all the commands sent to panel in dmesg in a nice way

image

Uncommented #define SMART_DIMMING_DEBUG allows us to see gamma tables dump, like this: a5lte-panel-gamma-tables.log (useful info is at the bottom)

But the most interesting are brightness change command dumps, take a look at https://paste.sr.ht/~minlexx/8dafcf2400372cb369a14cc767b027f770c045f4. They look a bit different from what I saw for klte panel, this driver wraps every sub-command with level2-key-enable/disable pairs (f0 5a 5a, f1 5a 5a ... f0 a5 a5, f1 a5 a5). Klte panel uses single "level2-key-enable" operation at the beginning of brightness change operation, then does all the thigs, and then "level2-key-disable". This driver is special, it wraps every command in those sequences.. Feel the difference, roughly:
klte:

  • enter level 2 mode
    • send aid
    • send elvss
    • send gamma
  • leave level 2 mode

a5lte:

  • enter level 2 mode, send aid, leave level 2 mode
  • enter level 2 mode, send elvss, leave level 2 mode
  • enter level 2 mode, send elvss, leave level 2 mode (again, for some reason??)
  • enter level 2 mode, send gamma, leave level 2 mode

🙈 this results in much longer sequences, and if we want to mimic downstream driver behaviour fully (I think we want) - this driver will need to be adjusted, as I currently don't see f0 5a 5a, f1 5a 5a .. sequences here at all.

@minlexx
Copy link

minlexx commented Jul 26, 2021

The explanation of "level 2 test keys" from linusw:

alexeymin: essentially commands intended to be used during manufacturing.
Just that Samsung tend to use it in deployment. Display manufacturers normally
have the same "firmware ambition" to make the display self-configure from factory
programmed "MTP" (manufacturing time programmable) settings.
Samsung doesn't do this. The reason can be to save cost (no flash EEPROM) or
speed up deployment and making it field-alterable.

Looks like it's important to exit from that programming mode after entering it, to avoid some display data (or other things) to be accidentally interpreted as some "MTP" command? Maybe we can do like klte's panel does, wrap the whole brightnes set operation in enter-exit pair at least, wrapping every subcommand seems like too much

@stephan-gh stephan-gh changed the base branch from master to backup/5.14-rc1/please-rebase August 5, 2021 09:08
@Grimler91
Copy link
Author

Grimler91 commented Aug 7, 2021

allows us to see gamma tables dump, like this: a5lte-panel-gamma-tables.log

Your dump differs a bit from the one I got, will check yours and see if the colors seem better.

see_no_evil this results in much longer sequences, and if we want to mimic downstream driver behaviour fully (I think we want)

Mimic'ing downstream is probably the safest, but the driver for a5lte is clearly written to be as generic as possible and to handle all possible types of panels, to make samsung's life easier. Really feels like unlocking and locking again on every command is something they have added because some panel (not necessarily ea8061v ams497ee01) needed it. If we look at other ea8061v drivers (and assuming they should work similarly, which we can't be sure of I guess), they do it more like klte does it (this is the driver my first version was based on, it also worked reasonably well).

this driver will need to be adjusted, as I currently don't see f0 5a 5a, f1 5a 5a .. sequences here at all.

I unlock them, and leave them unlocked, in the init function. Given the level 2 testkey explanation I definitely agree that they should be locked again, preferably in the way klte does it.

You had "B8 14" and "B5 21" in your dump, B8 14 probably sets some reference temperature to 20 deg C, since B8 19 seem to set reference temperature 25 degC, and B5 21 seem to be the "opposite" of B5 29.

@minlexx
Copy link

minlexx commented Aug 7, 2021

You had "B8 14" and "B5 21" in your dump, B8 14 probably sets some reference temperature to 20 deg C, since B8 19 seem to set reference temperature 25 degC, and B5 21 seem to be the "opposite" of B5 29.

Nice, then we can have functions named like ..._set_tset(), acl_off/acl_on or in some other meaningful way instead of "unknown bytes sequence"

@Grimler91 Grimler91 changed the base branch from backup/5.14-rc1/please-rebase to master August 11, 2021 19:41
@Grimler91
Copy link
Author

@minlexx I tested with the lux dump you captured but could not tell any difference from with what I have now. I guess the downstream driver can calculate a slightly different tables on different devices (since it is generated dynamically)

@TravMurav TravMurav changed the base branch from master to backup/5.14-rc5/please-rebase August 23, 2021 12:47
@stephan-gh stephan-gh changed the base branch from backup/5.14-rc5/please-rebase to msm8916/5.14-rc5 November 11, 2022 09:21
@stephan-gh stephan-gh changed the base branch from msm8916/5.14-rc5 to old/msm8916/5.14-rc5 November 11, 2022 09:41
@stephan-gh stephan-gh changed the title drm/panel: add backlight support to ea8061v-ams497ee01 driver WIP: drm/panel: add backlight support to ea8061v-ams497ee01 driver Nov 24, 2022
@stephan-gh stephan-gh changed the title WIP: drm/panel: add backlight support to ea8061v-ams497ee01 driver drm/panel: add backlight support to ea8061v-ams497ee01 driver Jan 30, 2023
@stephan-gh stephan-gh marked this pull request as draft January 30, 2023 17:47
@Grimler91 Grimler91 changed the base branch from old/msm8916/5.14-rc5 to msm8916/6.4-rc4 July 16, 2023 12:19
@Grimler91 Grimler91 marked this pull request as ready for review July 16, 2023 12:19
@stephan-gh
Copy link
Member

Do you have any plans to submit the full driver upstream?

If not, please keep the driver in msm8916-generated for now and just have incremental changes on top of the generated driver (even if they are quite large). That way we can still try to regenerate the base driver with refactorings made upstream and either have them merged in automatically or at least get a conflict that signifies the driver might need changes.

@Grimler91 Grimler91 force-pushed the msm8916-a5lte-backlight branch 3 times, most recently from a2691b6 to c9e5f5a Compare July 30, 2023 07:58
@Grimler91
Copy link
Author

Do you have any plans to submit the full driver upstream?

Not until the remaining flickering issue has been resolved at least.

If not, please keep the driver in msm8916-generated for now and just have incremental changes on top of the generated driver (even if they are quite large). That way we can still try to regenerate the base driver with refactorings made upstream and either have them merged in automatically or at least get a conflict that signifies the driver might need changes.

Sure, makes sense. I moved it back to msm8916-generated folder, and edited the Kconfig option in drivers/gpu/drm/panel/msm8916-generated instead.

@stephan-gh
Copy link
Member

Not until the remaining flickering issue has been resolved at least.

I think this is likely not an issue with your driver but rather in the Qualcomm/msm DSI implementation. Similar issues when changing the brightness levels via DSI commands also exist on other devices. It's not that bad there because they only need to send a single command though and not multiple like you here.

In other words, I think fixing the flickering does likely not involve any changes in the panel driver, but rather in the common msm DSI code.

Sure, makes sense. I moved it back to msm8916-generated folder, and edited the Kconfig option in drivers/gpu/drm/panel/msm8916-generated instead.

Thanks!

This patch adds support for Samsung's AMOLED AMS497EE01 panel with an
EA8061V controller. The driver is mostly based on the driver for
s6e3fa2 and s6e63m0, with data taken from the downstream android
kernel for the device with codename a500f.

The panel is used in the msm8916 Samsung Galaxy A5U (EUR) devices, for
which there is already partial support in the mainline kernel.

Signed-off-by: Henrik Grimler <henrik@grimler.se>
@Grimler91 Grimler91 changed the base branch from msm8916/6.4-rc4 to msm8916/6.5-rc5 August 7, 2023 19:58
stephan-gh pushed a commit that referenced this pull request Aug 14, 2023
BPF CI has reported the following failure:

Error: #200/79 sockmap_listen/sockmap VSOCK test_vsock_redir
  Error: #200/79 sockmap_listen/sockmap VSOCK test_vsock_redir
  ./test_progs:vsock_unix_redir_connectible:1506: egress: write: Transport endpoint is not connected
  vsock_unix_redir_connectible:FAIL:1506
  ./test_progs:vsock_unix_redir_connectible:1506: ingress: write: Transport endpoint is not connected
  vsock_unix_redir_connectible:FAIL:1506
  ./test_progs:vsock_unix_redir_connectible:1506: egress: write: Transport endpoint is not connected
  vsock_unix_redir_connectible:FAIL:1506
  ./test_progs:vsock_unix_redir_connectible:1514: ingress: recv() err, errno=11
  vsock_unix_redir_connectible:FAIL:1514
  ./test_progs:vsock_unix_redir_connectible:1518: ingress: vsock socket map failed, a != b
  vsock_unix_redir_connectible:FAIL:1518
  ./test_progs:vsock_unix_redir_connectible:1525: ingress: want pass count 1, have 0

It’s because the recv(... MSG_DONTWAIT) syscall in the test case is
called before the queued work sk_psock_backlog() in the kernel finishes
executing. So the data to be read is still queued in psock->ingress_skb
and cannot be read by the user program. Therefore, the non-blocking
recv() reads nothing and reports an EAGAIN error.

So replace recv(... MSG_DONTWAIT) with xrecv_nonblock(), which calls
select() to wait for data to be readable or timeout before calls recv().

Fixes: d61bd8c ("selftests/bpf: add a test case for vsock sockmap")
Signed-off-by: Xu Kuohai <xukuohai@huawei.com>
Link: https://lore.kernel.org/r/20230804073740.194770-4-xukuohai@huaweicloud.com
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
@stephan-gh
Copy link
Member

I tried to minimize the diff compared to the generated driver a bit more and pushed an updated version to your branch (I don't have permission for some reason, GitHub bug?). I pushed it to wip/msm8916/a5lte-backlight (2d54c1f). Can you check if this looks good to you and test if it still works?

Some notable differences:

  • The backlight handling is closer to the generated code now. It assigns the backlight to the drm_panel. With this, backlight_enable() and backlight_disable() happens automatically on the enable()/disable() calls and do not need to be handled in the driver (see drm_panel_enable()).
  • The mipi_dsi_dcs_exit_sleep_mode() in the enable() callback seems to be duplicated, since it's already in ea8061v_ams497ee01_init(). I just dropped the enable()/disable() callbacks entirely for consistency.

I noticed some more minor things, but I will add separate comments for these.

The main code for setting the actual brightness looks good to me, thanks for trying to understand the mess Samsung did there. :)

Backup of the previous version for reference
// SPDX-License-Identifier: GPL-2.0-only
// Copyright (c) 2023 FIXME
// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
//   Copyright (c) 2013, The Linux Foundation. All rights reserved. (FIXME)
//
// Mostly based on s6e3fa2 and s6e63m0. Table values dumped from
// Samsung's SM-A500F android kernel

#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>

#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/regulator/consumer.h>


#define EA8061V_AMS497EE01_NUM_GAMMA_LEVELS	62
#define EA8061V_AMS497EE01_GAMMA_CMD_CNT	34

#define EA8061V_AMS497EE01_MIN_BRIGHTNESS	0
#define EA8061V_AMS497EE01_MAX_BRIGHTNESS	(EA8061V_AMS497EE01_NUM_GAMMA_LEVELS - 1)
#define EA8061V_AMS497EE01_DEFAULT_BRIGHTNESS	40

/* Commands from manufacturer */
#define MCS_ACL_OFF		0x5c
#define MCS_ACL_ON		0x4c
#define MCS_ACL_CONTROL		0x55
#define MCS_AID_CONTROL		0xb2 /* Samsung AMOLED Impulsive Driving */
#define MCS_ACL_OPR_CONTROL	0xb5
#define MCS_ELVSS_CONTROL	0xb6 /* Amoled negative power supply */
#define MCS_TSET		0xb8 /* Set reference conditions */
#define MCS_GAMMA		0xca
#define MCS_GAMMA_UPDATE	0xf7

/* Which ELVSS sequence to use for which candela level.
 */
static const u8 map_candela_to_elvss[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS] = {
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	1, 1, 2, 2, 3, 4, 4, 5, 6,
	7, 7, 7, 8, 9, 10,
	11, 11, 11, 12, 13, 14, 15, 16, 17
};

static const u8 seq_ea8061v_ams497ee01_lux[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS][EA8061V_AMS497EE01_GAMMA_CMD_CNT] = {
	{ MCS_GAMMA,
	  0x00, 0x92, 0x00, 0xac, 0x00, 0x7e, 0x8a, 0x8f, 0x8b,
	  0x8d, 0x91, 0x8d, 0x96, 0xa1, 0x99, 0x9b, 0xa5, 0x00,
	  0x9c, 0x95, 0xa1, 0x8d, 0x9d, 0xa3, 0xa1, 0xba, 0xbb,
	  0xec, 0xbd, 0xd5, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x93, 0x00, 0xac, 0x00, 0x7e, 0x8b, 0x8e, 0x8b,
	  0x8d, 0x90, 0x8c, 0x93, 0x9e, 0x96, 0x94, 0xa1, 0x00,
	  0x96, 0x96, 0xa2, 0x8d, 0x9e, 0xa2, 0xa1, 0xb9, 0xba,
	  0xe1, 0xb4, 0xcd, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8a, 0x8d, 0x8a,
	  0x89, 0x8e, 0x8a, 0x92, 0x9d, 0x95, 0x95, 0xa1, 0x00,
	  0x97, 0x97, 0xa1, 0x8e, 0x98, 0xa0, 0x9d, 0xb3, 0xb7,
	  0xe0, 0xb3, 0xcb, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8b, 0x8d, 0x8b,
	  0x89, 0x8e, 0x8a, 0x92, 0x9c, 0x94, 0x93, 0x9e, 0x00,
	  0x96, 0x95, 0x9f, 0x8d, 0x98, 0xa0, 0x9c, 0xb2, 0xb4,
	  0xe9, 0xba, 0xd2, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x94, 0x00, 0xac, 0x00, 0x7f, 0x8a, 0x8c, 0x8b,
	  0x89, 0x8d, 0x89, 0x91, 0x9b, 0x94, 0x93, 0x9e, 0x00,
	  0x95, 0x94, 0x9e, 0x8c, 0x97, 0x9e, 0x9c, 0xb3, 0xb4,
	  0xde, 0xb1, 0xc5, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x95, 0x00, 0xac, 0x00, 0x80, 0x89, 0x8c, 0x8a,
	  0x8a, 0x8d, 0x8b, 0x90, 0x99, 0x92, 0x8f, 0x9a, 0x00,
	  0x93, 0x93, 0x9e, 0x8c, 0x99, 0x9e, 0x9c, 0xb1, 0xb3,
	  0xd9, 0xae, 0xbf, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8c, 0x8a,
	  0x89, 0x8b, 0x89, 0x90, 0x98, 0x92, 0x92, 0x9c, 0x00,
	  0x95, 0x90, 0x9b, 0x88, 0x98, 0x9e, 0x9c, 0xb1, 0xb1,
	  0xdd, 0xb0, 0xc3, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8c, 0x8a,
	  0x8a, 0x8b, 0x8a, 0x8e, 0x96, 0x91, 0x92, 0x9b, 0x00,
	  0x97, 0x92, 0x9b, 0x8a, 0x92, 0x9d, 0x96, 0xae, 0xae,
	  0xdc, 0xb0, 0xc2, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x89, 0x8b, 0x88,
	  0x8b, 0x8c, 0x8b, 0x8f, 0x96, 0x92, 0x8f, 0x99, 0x00,
	  0x93, 0x91, 0x9b, 0x88, 0x93, 0x9a, 0x98, 0xaf, 0xad,
	  0xe0, 0xb3, 0xc6, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x96, 0x00, 0xac, 0x00, 0x81, 0x8a, 0x8b, 0x89,
	  0x89, 0x8b, 0x87, 0x91, 0x97, 0x94, 0x8b, 0x96, 0x00,
	  0x91, 0x90, 0x9b, 0x89, 0x93, 0x9b, 0x95, 0xad, 0xac,
	  0xdf, 0xb3, 0xc5, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88,
	  0x89, 0x8b, 0x88, 0x90, 0x96, 0x92, 0x8f, 0x98, 0x00,
	  0x94, 0x8d, 0x98, 0x87, 0x93, 0x9a, 0x95, 0xad, 0xac,
	  0xdf, 0xb3, 0xc5, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88,
	  0x8a, 0x8b, 0x88, 0x90, 0x96, 0x92, 0x8c, 0x95, 0x00,
	  0x92, 0x8d, 0x98, 0x87, 0x92, 0x9a, 0x93, 0xae, 0xac,
	  0xd9, 0xae, 0xbf, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8b, 0x88,
	  0x8a, 0x8b, 0x88, 0x8e, 0x93, 0x90, 0x8e, 0x97, 0x00,
	  0x93, 0x8d, 0x98, 0x88, 0x92, 0x9a, 0x93, 0xa7, 0xa6,
	  0xea, 0xbb, 0xd1, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
	  0x88, 0x8a, 0x87, 0x8c, 0x93, 0x90, 0x8e, 0x96, 0x00,
	  0x93, 0x8a, 0x95, 0x84, 0x90, 0x98, 0x8f, 0xad, 0xab,
	  0xdb, 0xb0, 0xc2, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
	  0x88, 0x8a, 0x87, 0x8d, 0x93, 0x91, 0x8b, 0x93, 0x00,
	  0x91, 0x8e, 0x96, 0x88, 0x90, 0x98, 0x8e, 0xa6, 0xa5,
	  0xe3, 0xb7, 0xca, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
	  0x88, 0x8a, 0x87, 0x8d, 0x93, 0x91, 0x8c, 0x93, 0x00,
	  0x92, 0x89, 0x94, 0x83, 0x8c, 0x94, 0x8b, 0xab, 0xab,
	  0xd2, 0xab, 0xba, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
	  0x88, 0x8a, 0x87, 0x8c, 0x91, 0x8e, 0x8d, 0x93, 0x00,
	  0x92, 0x8c, 0x96, 0x86, 0x91, 0x98, 0x8f, 0xa6, 0xa6,
	  0xe7, 0xba, 0xce, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
	  0x89, 0x8a, 0x88, 0x8d, 0x92, 0x8f, 0x8d, 0x93, 0x00,
	  0x92, 0x89, 0x93, 0x83, 0x8f, 0x97, 0x8f, 0xa4, 0xa4,
	  0xd7, 0xae, 0xbf, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8b, 0x8a,
	  0x88, 0x89, 0x87, 0x8d, 0x92, 0x8f, 0x8d, 0x92, 0x00,
	  0x92, 0x89, 0x93, 0x83, 0x8c, 0x94, 0x8b, 0xa2, 0xa2,
	  0xe7, 0xba, 0xce, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
	  0x89, 0x8a, 0x88, 0x8d, 0x91, 0x90, 0x89, 0x8f, 0x00,
	  0x8f, 0x8c, 0x95, 0x84, 0x8b, 0x94, 0x8a, 0xa2, 0xa0,
	  0xe1, 0xb6, 0xc8, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
	  0x89, 0x8a, 0x88, 0x8e, 0x91, 0x90, 0x89, 0x8f, 0x00,
	  0x90, 0x88, 0x91, 0x81, 0x8c, 0x94, 0x8a, 0xa6, 0xa6,
	  0xd6, 0xae, 0xbe, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
	  0x89, 0x8a, 0x88, 0x8d, 0x90, 0x90, 0x89, 0x8f, 0x00,
	  0x8f, 0x88, 0x91, 0x81, 0x8c, 0x93, 0x8a, 0xa7, 0xa6,
	  0xd1, 0xaa, 0xb8, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x8a, 0x89,
	  0x89, 0x8a, 0x88, 0x8e, 0x90, 0x90, 0x86, 0x8c, 0x00,
	  0x8e, 0x87, 0x90, 0x7f, 0x8f, 0x96, 0x8e, 0xa2, 0xa0,
	  0xd6, 0xad, 0xbd, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x88, 0x89, 0x87, 0x8d, 0x8f, 0x8f, 0x88, 0x8d, 0x00,
	  0x90, 0x87, 0x90, 0x7f, 0x8f, 0x96, 0x8e, 0xa2, 0xa0,
	  0xd6, 0xad, 0xbd, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x89, 0x87, 0x8c, 0x8f, 0x8f, 0x8a, 0x8d, 0x00,
	  0x91, 0x88, 0x90, 0x81, 0x8b, 0x93, 0x8a, 0xa1, 0x9e,
	  0xcf, 0xa9, 0xb7, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x89, 0x87, 0x8a, 0x8e, 0x8e, 0x89, 0x8c, 0x00,
	  0x91, 0x87, 0x8f, 0x7f, 0x90, 0x96, 0x90, 0x99, 0x97,
	  0xe0, 0xb5, 0xc8, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x89, 0x87, 0x8b, 0x8e, 0x8f, 0x89, 0x8c, 0x00,
	  0x91, 0x87, 0x8f, 0x7f, 0x89, 0x91, 0x88, 0x9f, 0x9e,
	  0xda, 0xb1, 0xc2, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x89, 0x87, 0x8b, 0x8e, 0x8f, 0x87, 0x89, 0x00,
	  0x8f, 0x87, 0x8d, 0x7e, 0x8f, 0x95, 0x8d, 0x9a, 0x97,
	  0xd4, 0xad, 0xbc, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x8a, 0x89, 0x88, 0x8a, 0x8e, 0x8e, 0x88, 0x89, 0x00,
	  0x90, 0x81, 0x8a, 0x79, 0x93, 0x98, 0x92, 0x9b, 0x98,
	  0xd4, 0xad, 0xbc, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x88, 0x87, 0x89, 0x8d, 0x8d, 0x8a, 0x8b, 0x00,
	  0x91, 0x81, 0x8a, 0x79, 0x93, 0x97, 0x92, 0x9b, 0x98,
	  0xba, 0x9d, 0xa8, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x88, 0x87, 0x8a, 0x8d, 0x8e, 0x86, 0x88, 0x00,
	  0x8e, 0x87, 0x8d, 0x7d, 0x8e, 0x93, 0x8e, 0x94, 0x91,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x88, 0x87, 0x8a, 0x8d, 0x8e, 0x87, 0x88, 0x00,
	  0x8f, 0x82, 0x89, 0x79, 0x8d, 0x92, 0x8b, 0x97, 0x95,
	  0xdf, 0xb5, 0xc7, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x86, 0x88, 0x00,
	  0x8f, 0x82, 0x88, 0x79, 0x8c, 0x92, 0x8b, 0x99, 0x96,
	  0xd2, 0xad, 0xbc, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x8a, 0x8a, 0x89,
	  0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x86, 0x87, 0x00,
	  0x8f, 0x82, 0x88, 0x79, 0x8d, 0x92, 0x8c, 0x9b, 0x97,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x97, 0x00, 0xac, 0x00, 0x82, 0x89, 0x89, 0x88,
	  0x8a, 0x89, 0x88, 0x8b, 0x8d, 0x8e, 0x86, 0x87, 0x00,
	  0x8f, 0x83, 0x88, 0x7a, 0x8e, 0x92, 0x8d, 0x93, 0x8f,
	  0xbc, 0xa1, 0xac, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0x9b, 0x00, 0xaf, 0x00, 0x87, 0x88, 0x89, 0x88,
	  0x89, 0x88, 0x87, 0x8b, 0x8d, 0x8e, 0x87, 0x86, 0x00,
	  0x8f, 0x83, 0x88, 0x7a, 0x8e, 0x92, 0x8d, 0x94, 0x90,
	  0xa1, 0x91, 0x97, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xa0, 0x00, 0xb3, 0x00, 0x8d, 0x89, 0x89, 0x88,
	  0x89, 0x88, 0x86, 0x8b, 0x8c, 0x8d, 0x85, 0x85, 0x00,
	  0x8d, 0x84, 0x89, 0x7c, 0x8a, 0x8e, 0x89, 0x93, 0x8f,
	  0xca, 0xa9, 0xb7, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xa4, 0x00, 0xb6, 0x00, 0x92, 0x88, 0x89, 0x89,
	  0x88, 0x87, 0x86, 0x8a, 0x8b, 0x8b, 0x87, 0x86, 0x00,
	  0x8c, 0x81, 0x86, 0x79, 0x89, 0x8e, 0x88, 0x9b, 0x98,
	  0x81, 0x7d, 0x7d, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xa8, 0x00, 0xba, 0x00, 0x97, 0x88, 0x88, 0x88,
	  0x88, 0x87, 0x86, 0x87, 0x8b, 0x8a, 0x8a, 0x88, 0x00,
	  0x8f, 0x83, 0x88, 0x7d, 0x87, 0x8c, 0x87, 0x95, 0x91,
	  0xa9, 0x95, 0x9d, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xad, 0x00, 0xbe, 0x00, 0x9d, 0x87, 0x88, 0x88,
	  0x88, 0x87, 0x86, 0x8a, 0x8b, 0x8c, 0x86, 0x85, 0x00,
	  0x89, 0x82, 0x88, 0x7d, 0x87, 0x8b, 0x87, 0x96, 0x91,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xb1, 0x00, 0xc1, 0x00, 0xa2, 0x87, 0x88, 0x88,
	  0x88, 0x87, 0x86, 0x87, 0x89, 0x89, 0x87, 0x86, 0x00,
	  0x8b, 0x80, 0x85, 0x7b, 0x8c, 0x8f, 0x8c, 0x8f, 0x8c,
	  0xc4, 0xa5, 0xb2, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xb7, 0x00, 0xc5, 0x00, 0xa8, 0x86, 0x87, 0x87,
	  0x88, 0x86, 0x85, 0x88, 0x89, 0x89, 0x87, 0x86, 0x00,
	  0x8a, 0x81, 0x86, 0x7d, 0x8a, 0x8d, 0x88, 0x8f, 0x8c,
	  0xb7, 0x9d, 0xa7, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xbc, 0x00, 0xc9, 0x00, 0xae, 0x86, 0x87, 0x87,
	  0x87, 0x86, 0x85, 0x87, 0x88, 0x87, 0x86, 0x87, 0x00,
	  0x8a, 0x80, 0x84, 0x7b, 0x8a, 0x8c, 0x88, 0x90, 0x8d,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xc1, 0x00, 0xcd, 0x00, 0xb4, 0x86, 0x87, 0x87,
	  0x87, 0x86, 0x86, 0x86, 0x88, 0x87, 0x87, 0x86, 0x00,
	  0x88, 0x82, 0x84, 0x7c, 0x85, 0x89, 0x86, 0x91, 0x8e,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xc6, 0x00, 0xd1, 0x00, 0xba, 0x85, 0x86, 0x86,
	  0x86, 0x85, 0x85, 0x85, 0x86, 0x86, 0x88, 0x87, 0x00,
	  0x89, 0x82, 0x86, 0x7d, 0x80, 0x86, 0x82, 0x91, 0x8e,
	  0xb7, 0x9d, 0xa7, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xca, 0x00, 0xd4, 0x00, 0xbf, 0x86, 0x87, 0x87,
	  0x86, 0x85, 0x85, 0x85, 0x86, 0x86, 0x86, 0x84, 0x00,
	  0x86, 0x82, 0x85, 0x7f, 0x80, 0x86, 0x82, 0x91, 0x8e,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xd0, 0x00, 0xd9, 0x00, 0xc6, 0x84, 0x85, 0x85,
	  0x85, 0x84, 0x84, 0x83, 0x85, 0x84, 0x86, 0x85, 0x00,
	  0x86, 0x7f, 0x82, 0x7c, 0x87, 0x8a, 0x87, 0x8e, 0x8a,
	  0x9c, 0x8d, 0x92, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xd5, 0x00, 0xdd, 0x00, 0xcc, 0x85, 0x86, 0x86,
	  0x85, 0x84, 0x84, 0x82, 0x84, 0x83, 0x86, 0x85, 0x00,
	  0x85, 0x80, 0x83, 0x7e, 0x83, 0x86, 0x84, 0x8d, 0x89,
	  0xa9, 0x95, 0x9d, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd3, 0x84, 0x84, 0x84,
	  0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x86, 0x85, 0x00,
	  0x85, 0x83, 0x85, 0x7f, 0x7f, 0x84, 0x81, 0x8f, 0x8b,
	  0x8f, 0x85, 0x88, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
	  0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x86, 0x85, 0x00,
	  0x85, 0x84, 0x85, 0x80, 0x7f, 0x83, 0x81, 0x8f, 0x8b,
	  0x74, 0x75, 0x73, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
	  0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x83, 0x84, 0x00,
	  0x84, 0x82, 0x83, 0x7f, 0x7f, 0x81, 0x80, 0x8e, 0x8a,
	  0x85, 0x81, 0x81, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
	  0x83, 0x83, 0x83, 0x84, 0x84, 0x85, 0x83, 0x84, 0x00,
	  0x84, 0x7f, 0x80, 0x7b, 0x83, 0x85, 0x85, 0x87, 0x84,
	  0xa5, 0x94, 0x9c, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
	  0x83, 0x83, 0x83, 0x82, 0x83, 0x83, 0x82, 0x82, 0x00,
	  0x83, 0x82, 0x82, 0x7e, 0x82, 0x85, 0x85, 0x89, 0x85,
	  0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
	  0x83, 0x83, 0x83, 0x82, 0x83, 0x83, 0x83, 0x82, 0x00,
	  0x84, 0x81, 0x82, 0x7d, 0x83, 0x85, 0x85, 0x86, 0x86,
	  0x97, 0x8c, 0x91, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x84, 0x84, 0x84,
	  0x82, 0x82, 0x82, 0x83, 0x84, 0x84, 0x84, 0x82, 0x00,
	  0x84, 0x82, 0x82, 0x7e, 0x7e, 0x80, 0x80, 0x8d, 0x8b,
	  0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xda, 0x00, 0xe1, 0x00, 0xd2, 0x83, 0x84, 0x84,
	  0x84, 0x84, 0x84, 0x82, 0x83, 0x83, 0x82, 0x82, 0x00,
	  0x85, 0x82, 0x82, 0x7e, 0x84, 0x85, 0x85, 0x8b, 0x8a,
	  0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xe0, 0x00, 0xe6, 0x00, 0xda, 0x83, 0x83, 0x83,
	  0x83, 0x82, 0x82, 0x83, 0x83, 0x83, 0x82, 0x81, 0x00,
	  0x84, 0x83, 0x83, 0x80, 0x81, 0x81, 0x81, 0x8b, 0x8a,
	  0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xe6, 0x00, 0xeb, 0x00, 0xe1, 0x82, 0x83, 0x83,
	  0x83, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x00,
	  0x83, 0x84, 0x84, 0x82, 0x83, 0x83, 0x83, 0x86, 0x85,
	  0x89, 0x84, 0x86, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xec, 0x00, 0xf0, 0x00, 0xe8, 0x82, 0x83, 0x83,
	  0x81, 0x81, 0x81, 0x80, 0x81, 0x81, 0x82, 0x82, 0x00,
	  0x83, 0x81, 0x81, 0x80, 0x83, 0x83, 0x83, 0x86, 0x85,
	  0x89, 0x84, 0x86, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xf1, 0x00, 0xf4, 0x00, 0xee, 0x81, 0x81, 0x81,
	  0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x81, 0x80, 0x00,
	  0x82, 0x81, 0x81, 0x80, 0x83, 0x83, 0x83, 0x86, 0x85,
	  0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x00, 0xf6, 0x00, 0xf8, 0x00, 0xf4, 0x82, 0x82, 0x82,
	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00,
	  0x81, 0x82, 0x82, 0x81, 0x7f, 0x7f, 0x7f, 0x86, 0x85,
	  0x7b, 0x7c, 0x7b, 0x00, 0x00, 0x00 },
	{ MCS_GAMMA,
	  0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80, 0x80, 0x80,
	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
	  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
	  0x80, 0x80, 0x80, 0x00, 0x00, 0x00 }
};

/* ELVSS (Amoled negative power supply) tables */
#define EA8061V_AMS497EE01_NUM_ELVSS_SEQUENCES	18
#define ELVSS_SEQUENCE_LEN			3
static const u8 seq_ea8061v_ams497ee01_elvss[EA8061V_AMS497EE01_NUM_ELVSS_SEQUENCES][ELVSS_SEQUENCE_LEN] = {
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x9b },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x9a },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x99 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x98 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x97 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x96 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x95 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x94 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x93 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x92 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x91 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x90 },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8f },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8e },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8d },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8c },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8b },
	{ MCS_ELVSS_CONTROL, MCS_ACL_OFF, 0x8a }
};

#define EA8061V_AMS497EE01_NUM_AID_LEVELS	42
#define EA8061V_AMS497EE01_AID_CMD_CNT		5
/* Which AID sequence to use for each candela level.
 */
static const u8 map_candela_to_aid[EA8061V_AMS497EE01_NUM_GAMMA_LEVELS] = {
	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
	12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
	24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 34,
	34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34,
	34, 35, 36, 37, 38, 39, 40, 41, 41, 41, 41, 41,
	41, 41
};

static const u8 seq_ea8061v_ams497ee01_aid[EA8061V_AMS497EE01_NUM_AID_LEVELS][EA8061V_AMS497EE01_AID_CMD_CNT] = {
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xdf }, /* 95.63 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xd3 }, /* 94.71 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xc7 }, /* 93.79 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xbb }, /* 92.87 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xb0 }, /* 92.02 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0xa4 }, /* 91.10 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x99 }, /* 90.26 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x8d }, /* 89.34 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x82 }, /* 88.50 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x76 }, /* 87.58 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x6a }, /* 86.66 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x5f }, /* 85.81 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x52 }, /* 84.82 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x3b }, /* 83.05 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x31 }, /* 82.29 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x25 }, /* 81.37 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x18 }, /* 80.37 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x04, 0x01 }, /* 78.60 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xf5 }, /* 77.68 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xdb }, /* 75.69 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xc5 }, /* 74.00 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0xb7 }, /* 72.93 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x9e }, /* 71.01 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x88 }, /* 69.33 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x64 }, /* 66.56 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x4b }, /* 64.64 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x32 }, /* 62.73 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x03, 0x0d }, /* 59.89 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0xe7 }, /* 56.98 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0xc2 }, /* 54.14 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x9d }, /* 51.30 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x79 }, /* 48.54 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x45 }, /* 44.56 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x02, 0x13 }, /* 40.72 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0xe7 }, /* 37.35 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0xae }, /* 32.98 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0x76 }, /* 28.68 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x01, 0x39 }, /* 24.00 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0xf8 }, /* 19.02 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0xb4 }, /* 13.80 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0x63 }, /*  7.59 % */
	{ MCS_AID_CONTROL, 0x00, 0x00, 0x00, 0x0a }  /*  0.77 % */
};

struct ea8061v_ams497ee01 {
	struct drm_panel panel;
	struct mipi_dsi_device *dsi;

	struct backlight_device *bl_dev;

	struct regulator_bulk_data supplies[2];
	struct gpio_desc *reset_gpio;

	bool prepared;
	bool enabled;
};

static inline
struct ea8061v_ams497ee01 *to_ea8061v_ams497ee01(struct drm_panel *panel)
{
	return container_of(panel, struct ea8061v_ams497ee01, panel);
}

static int ea8061v_ams497ee01_unlock(struct ea8061v_ams497ee01 *ctx, u8 lock)
{
	switch (lock) {
	case 0xf0:
		mipi_dsi_dcs_write_seq(ctx->dsi, 0xf0, 0x5a, 0x5a);
		break;
	case 0xf1:
		mipi_dsi_dcs_write_seq(ctx->dsi, 0xf1, 0x5a, 0x5a);
		break;
	case 0xfc:
		mipi_dsi_dcs_write_seq(ctx->dsi, 0xfc, 0x5a, 0x5a);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int ea8061v_ams497ee01_lock(struct ea8061v_ams497ee01 *ctx, u8 lock)
{
	switch (lock) {
	case 0xf0:
		mipi_dsi_dcs_write_seq(ctx->dsi, 0xf0, 0xa5, 0xa5);
		break;
	case 0xf1:
		mipi_dsi_dcs_write_seq(ctx->dsi, 0xf1, 0xa5, 0xa5);
		break;
	case 0xfc:
		mipi_dsi_dcs_write_seq(ctx->dsi, 0xfc, 0xa5, 0xa5);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

static int ea8061v_ams497ee01_apply_gamma(struct ea8061v_ams497ee01 *ctx)
{
	mipi_dsi_dcs_write_seq(ctx->dsi, MCS_GAMMA_UPDATE, 0x01);
	return 0;
}

static int ea8061v_ams497ee01_update_aid(struct ea8061v_ams497ee01 *ctx,
					 unsigned int brightness)
{
	int ret;
	int index = map_candela_to_aid[brightness];

	ret = mipi_dsi_dcs_write_buffer(ctx->dsi,
					seq_ea8061v_ams497ee01_aid[index],
					EA8061V_AMS497EE01_AID_CMD_CNT);
	if (ret < 0)
		return ret;
	return 0;
}

static int ea8061v_ams497ee01_update_elvss(struct ea8061v_ams497ee01 *ctx,
					   unsigned int brightness)
{
	int ret;
	int index = map_candela_to_elvss[brightness];

	ret = mipi_dsi_dcs_write_buffer(ctx->dsi,
					seq_ea8061v_ams497ee01_elvss[index],
					ELVSS_SEQUENCE_LEN);
	if (ret < 0)
		return ret;
	return 0;
}

static int ea8061v_ams497ee01_update_gamma(struct ea8061v_ams497ee01 *ctx,
					   unsigned int brightness)
{
	int ret;
	struct backlight_device *bl_dev = ctx->bl_dev;

	ret = mipi_dsi_dcs_write_buffer(ctx->dsi,
					seq_ea8061v_ams497ee01_lux[brightness],
					EA8061V_AMS497EE01_GAMMA_CMD_CNT);
	if (ret < 0)
		return ret;

	bl_dev->props.brightness = brightness;

	return 0;
}

static int ea8061v_ams497ee01_set_brightness(struct backlight_device *bl_dev)
{
	struct ea8061v_ams497ee01 *ctx = bl_get_data(bl_dev);
	unsigned int brightness = bl_dev->props.brightness;
	struct mipi_dsi_device *dsi = ctx->dsi;
	struct device *dev = &dsi->dev;
	int ret;

	ret = ea8061v_ams497ee01_unlock(ctx, 0xf0);
	if (ret < 0) {
		dev_err(dev, "Failed to unlock 0xf0: %d\n", ret);
		return ret;
	}
	ret = ea8061v_ams497ee01_unlock(ctx, 0xf1);
	if (ret < 0) {
		dev_err(dev, "Failed to unlock 0xf1: %d\n", ret);
		return ret;
	}

	/* aid/aor */
	ret = ea8061v_ams497ee01_update_aid(ctx, brightness);
	if (ret < 0) {
		dev_err(dev, "Failed to send aid sequence: %d\n", ret);
		return ret;
	}
	mipi_dsi_dcs_write_seq(dsi, MCS_ACL_OPR_CONTROL, 0x29);
	mipi_dsi_dcs_write_seq(dsi, MCS_ACL_CONTROL, 0x00);

	ret = ea8061v_ams497ee01_update_elvss(ctx, brightness);
	if (ret < 0) {
		dev_err(dev, "Failed to update elvss: %d\n", ret);
		return ret;
	}

	ret = ea8061v_ams497ee01_update_gamma(ctx, brightness);
	if (ret < 0) {
		dev_err(dev, "Failed to update gamma: %d\n", ret);
		return ret;
	}

	ret = ea8061v_ams497ee01_apply_gamma(ctx);
	if (ret < 0) {
		dev_err(dev, "Failed to apply gamma update: %d\n", ret);
		return ret;
	}

	ea8061v_ams497ee01_lock(ctx, 0xf1);
	if (ret < 0) {
		dev_err(dev, "Failed to lock 0xf1: %d\n", ret);
		return ret;
	}
	ea8061v_ams497ee01_lock(ctx, 0xf0);
	if (ret < 0) {
		dev_err(dev, "Failed to lock 0xf0: %d\n", ret);
		return ret;
	}

	return 0;
}

static const struct backlight_ops ea8061v_ams497ee01_bl_ops = {
	.update_status = ea8061v_ams497ee01_set_brightness,
};

static int ea8061v_ams497ee01_init(struct ea8061v_ams497ee01 *ctx)
{
	struct mipi_dsi_device *dsi = ctx->dsi;
	struct device *dev = &dsi->dev;
	int ret;

	unsigned int brightness = ctx->bl_dev->props.brightness;

	dsi->mode_flags |= MIPI_DSI_MODE_LPM;

	ret = ea8061v_ams497ee01_unlock(ctx, 0xf0);
	if (ret < 0) {
		dev_err(dev, "Failed to unlock 0xf0: %d\n", ret);
		return ret;
	}
	ret = ea8061v_ams497ee01_unlock(ctx, 0xf1);
	if (ret < 0) {
		dev_err(dev, "Failed to unlock 0xf1: %d\n", ret);
		return ret;
	}

	/* Common conditions */
	/* set ref temperature/voltage (0x19 = 25 degC, 0x10 = 7.6 V) */
	mipi_dsi_dcs_write_seq(dsi, MCS_TSET, 0x19, 0x10);
	/* ? */
	mipi_dsi_dcs_write_seq(dsi, 0xba, 0x57);

	ret = ea8061v_ams497ee01_unlock(ctx, 0xfc);
	if (ret < 0) {
		dev_err(dev, "Failed to unlock 0xfc: %d\n", ret);
		return ret;
	}

	/* skip 11 parameters in HBM sequence? */
	mipi_dsi_dcs_write_seq(dsi, 0xb0, 0x0b);
	/* ? */
	mipi_dsi_dcs_write_seq(dsi, 0xd2, 0x00, 0x85);
	/* ? */
	mipi_dsi_dcs_write_seq(dsi, 0xcb, 0x70);

	ret = ea8061v_ams497ee01_lock(ctx, 0xfc);
	if (ret < 0) {
		dev_err(dev, "Failed to lock 0xfc: %d\n", ret);
		return ret;
	}
	/* Brightness control */
	ret = ea8061v_ams497ee01_update_gamma(ctx, brightness);
	if (ret < 0) {
		dev_err(dev, "Failed to update gamma: %d\n", ret);
		return ret;
	}
	ret = ea8061v_ams497ee01_update_aid(ctx, brightness);
	if (ret < 0) {
		dev_err(dev, "Failed to send aid sequence: %d\n", ret);
		return ret;
	}
	ret = ea8061v_ams497ee01_update_elvss(ctx, brightness);
	if (ret < 0) {
		dev_err(dev, "Failed to update elvss: %d\n", ret);
		return ret;
	}
	ret = ea8061v_ams497ee01_apply_gamma(ctx);
	if (ret < 0) {
		dev_err(dev, "Failed to apply gamma update: %d\n", ret);
		return ret;
	}

	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
	if (ret < 0) {
		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
		return ret;
	}
	msleep(120);

	ret = ea8061v_ams497ee01_lock(ctx, 0xf1);
	if (ret < 0) {
		dev_err(dev, "Failed to lock 0xf1: %d\n", ret);
		return ret;
	}

	ret = mipi_dsi_dcs_set_display_on(dsi);
	if (ret < 0) {
		dev_err(dev, "Failed to set display on: %d\n", ret);
		return ret;
	}

	return 0;
}

static int ea8061v_ams497ee01_power_on(struct ea8061v_ams497ee01 *ctx)
{
	int ret;

	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
	if (ret < 0) {
		dev_err(&ctx->dsi->dev,
			"Failed to enable regulators: %d\n", ret);
		return ret;
	}

	/* send reset pulse */
	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
	msleep(20);
	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
	usleep_range(1000, 2000);
	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
	msleep(20);

	return 0;
}

static int ea8061v_ams497ee01_power_off(struct ea8061v_ams497ee01 *ctx)
{
	int ret;

	gpiod_set_value(ctx->reset_gpio, 1);

	ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
	if (ret < 0)
		return ret;

	return 0;
}

static int ea8061v_ams497ee01_enable(struct drm_panel *panel)
{
	struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
	struct mipi_dsi_device *dsi = ctx->dsi;
	int ret;

	if (ctx->prepared)
		return 0;

	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
	if (ret < 0) {
		dev_err(&dsi->dev, "Failed to exit sleep mode: %d\n", ret);
		return ret;
	};
	msleep(120);

	backlight_enable(ctx->bl_dev);

	ctx->enabled = true;
	return 0;
}

static int ea8061v_ams497ee01_disable(struct drm_panel *panel)
{
	struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
	struct mipi_dsi_device *dsi = ctx->dsi;
	int ret;

	if (!ctx->enabled)
		return 0;

	backlight_disable(ctx->bl_dev);

	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;

	ret = mipi_dsi_dcs_set_display_off(dsi);
	if (ret < 0) {
		dev_err(&dsi->dev, "Failed to set display off: %d\n", ret);
		return ret;
	}
	msleep(35);

	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
	if (ret < 0) {
		dev_err(&dsi->dev, "Failed to enter sleep mode: %d\n", ret);
		return ret;
	}
	msleep(100);

	ctx->enabled = false;
	return 0;
}

static int ea8061v_ams497ee01_prepare(struct drm_panel *panel)
{
	struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
	struct device *dev = &ctx->dsi->dev;
	int ret;

	if (ctx->prepared)
		return 0;

	ret = ea8061v_ams497ee01_power_on(ctx);
	if (ret < 0) {
		dev_err(dev, "Failed to power on panel: %d\n", ret);
		return ret;
	}

	ret = ea8061v_ams497ee01_init(ctx);
	if (ret < 0) {
		dev_err(dev, "Failed to initialize panel: %d\n", ret);
		ea8061v_ams497ee01_power_off(ctx);
		return ret;
	}

	ctx->prepared = true;
	return 0;
}

static int ea8061v_ams497ee01_unprepare(struct drm_panel *panel)
{
	struct ea8061v_ams497ee01 *ctx = to_ea8061v_ams497ee01(panel);
	struct device *dev = &ctx->dsi->dev;
	int ret;

	if (!ctx->prepared)
		return 0;

	ret = ea8061v_ams497ee01_power_off(ctx);
	if (ret < 0)
		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);

	ctx->prepared = false;
	return 0;
}

static const struct drm_display_mode ea8061v_ams497ee01_mode = {
	.clock = (720 + 80 + 96 + 128) * (1280 + 14 + 2 + 8) * 60 / 1000,
	.hdisplay = 720,
	.hsync_start = 720 + 80,
	.hsync_end = 720 + 80 + 96,
	.htotal = 720 + 80 + 96 + 128,
	.vdisplay = 1280,
	.vsync_start = 1280 + 14,
	.vsync_end = 1280 + 14 + 2,
	.vtotal = 1280 + 14 + 2 + 8,
	.width_mm = 62,
	.height_mm = 110,
};

static int ea8061v_ams497ee01_get_modes(struct drm_panel *panel,
					struct drm_connector *connector)
{
	struct drm_display_mode *mode;

	mode = drm_mode_duplicate(connector->dev, &ea8061v_ams497ee01_mode);
	if (!mode)
		return -ENOMEM;

	drm_mode_set_name(mode);

	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
	connector->display_info.width_mm = mode->width_mm;
	connector->display_info.height_mm = mode->height_mm;
	drm_mode_probed_add(connector, mode);

	return 1;
}

static const struct drm_panel_funcs ea8061v_ams497ee01_panel_funcs = {
	.prepare = ea8061v_ams497ee01_prepare,
	.enable = ea8061v_ams497ee01_enable,
	.disable = ea8061v_ams497ee01_disable,
	.unprepare = ea8061v_ams497ee01_unprepare,
	.get_modes = ea8061v_ams497ee01_get_modes,
};

static int ea8061v_ams497ee01_probe(struct mipi_dsi_device *dsi)
{
	struct device *dev = &dsi->dev;
	struct ea8061v_ams497ee01 *ctx;
	int ret;

	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
	if (!ctx)
		return -ENOMEM;

	ctx->dsi = dsi;
	mipi_dsi_set_drvdata(dsi, ctx);

	ctx->supplies[0].supply = "vdd3";
	ctx->supplies[1].supply = "vci";
	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
				      ctx->supplies);
	if (ret < 0)
		return dev_err_probe(dev, ret, "Failed to get regulators\n");

	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
	if (IS_ERR(ctx->reset_gpio))
		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
				     "Failed to get reset-gpios\n");

	ctx->bl_dev = backlight_device_register("panel", dev, ctx,
						&ea8061v_ams497ee01_bl_ops,
						NULL);

	dsi->lanes = 4;
	dsi->format = MIPI_DSI_FMT_RGB888;
	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
			  MIPI_DSI_MODE_NO_EOT_PACKET;

	if (IS_ERR(ctx->bl_dev)) {
		dev_err(dev, "Failed to register backlight device\n");
		return PTR_ERR(ctx->bl_dev);
	}

	ctx->bl_dev->props.max_brightness = EA8061V_AMS497EE01_MAX_BRIGHTNESS;
	ctx->bl_dev->props.brightness = EA8061V_AMS497EE01_DEFAULT_BRIGHTNESS;
	ctx->bl_dev->props.power = FB_BLANK_POWERDOWN;

	drm_panel_init(&ctx->panel, dev, &ea8061v_ams497ee01_panel_funcs,
		       DRM_MODE_CONNECTOR_DSI);
	ctx->panel.prepare_prev_first = true;

	drm_panel_add(&ctx->panel);

	ret = mipi_dsi_attach(dsi);
	if (ret < 0) {
		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
		drm_panel_remove(&ctx->panel);
		return ret;
	}

	return 0;
}

static void ea8061v_ams497ee01_remove(struct mipi_dsi_device *dsi)
{
	struct ea8061v_ams497ee01 *ctx = mipi_dsi_get_drvdata(dsi);
	int ret;

	ret = mipi_dsi_detach(dsi);
	if (ret < 0)
		dev_err(&dsi->dev,
			"Failed to detach from DSI host: %d\n", ret);

	drm_panel_remove(&ctx->panel);
}

static const struct of_device_id ea8061v_ams497ee01_of_match[] = {
	{ .compatible = "samsung,ea8061v-ams497ee01" },
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ea8061v_ams497ee01_of_match);

static struct mipi_dsi_driver ea8061v_ams497ee01_driver = {
	.probe = ea8061v_ams497ee01_probe,
	.remove = ea8061v_ams497ee01_remove,
	.driver = {
		.name = "panel-ea8061v-ams497ee01",
		.of_match_table = ea8061v_ams497ee01_of_match,
	},
};
module_mipi_dsi_driver(ea8061v_ams497ee01_driver);

MODULE_AUTHOR("linux-mdss-dsi-panel-driver-generator <fix@me>"); // FIXME
MODULE_DESCRIPTION("DRM driver for ss_dsi_panel_EA8061V_AMS497EE01_HD");
MODULE_LICENSE("GPL");

usleep_range(1000, 2000);
gpiod_set_value_cansleep(ctx->reset_gpio, 0);
msleep(20);
switch (lock) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this switch? Can't you just do mipi_dsi_dcs_write_seq(ctx->dsi, lock, 0x5a, 0x5a);?

struct mipi_dsi_device *dsi = ctx->dsi;
struct device *dev = &dsi->dev;
int ret;

ret = ea8061v_ams497ee01_unlock(ctx, 0xf0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you know if these commands need to be sent in LPM or HPM? The generator typically produces something like

	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;

	ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
	if (ret < 0)
		return ret;

	dsi->mode_flags |= MIPI_DSI_MODE_LPM;

to make sure these commands are sent in HPM. (Now that I look at it the logic seems broken in case there is an error and return happens early but that's unrelated).

I'm not entirely sure but https://github.com/msm8916-mainline/linux-downstream/blob/3b09f23015d2f0949d49fb81ea1f43c63a8be503/drivers/video/msm/mdss/mdss_dsi_panel.c#L1041-L1044 seems to suggest you should also unset MIPI_DSI_MODE_LPM. Does that change anything for the brightness change "flickering"?

static int ea8061v_ams497ee01_set_brightness(struct backlight_device *bl_dev)
{
struct ea8061v_ams497ee01 *ctx = bl_get_data(bl_dev);
unsigned int brightness = bl_dev->props.brightness;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't entirely clear to me here if this can be replaced with backlight_get_brightness(). Usually backlight_get_brightness() is nicer because it returns 0 if the backlight has been "blanked" without changing the brightness to 0.

However, in general I'm actually unsure about the behavior when turning the screen on/off. I would expect that the backlight update_status() is called when doing backlight_enable()/backlight_disable(), which happens during the enable()/disable() callbacks. This is because update_status() is not just for brightness but also the blanking state ("on", "off"). This means that:

  • When enabling: The initial brightness is set twice, once by ea8061v_ams497ee01_init() and once by ea8061v_ams497ee01_set_brightness(). Given the amount of commands that need to be sent this isn't entirely ideal for speeding up panel enabling/disabling.
  • When disabling: The brightness is set to 0 before the panel gets disabled. This is probably okay, but might be unneeded.

For enabling, I guess this means you could omit the brightness setting in ea8061v_ams497ee01_init(), and expect it to be done by ea8061v_ams497ee01_set_brightness(). The tricky part is that I'm not sure if enabling the panel without any gamma/aid/elvss is safe.

Alternatively, it might help to "cache" the last brightness that was actually set, and skip the update in ea8061v_ams497ee01_set_brightness() if it didn't really change.

if (ret < 0)
return ret;

bl_dev->props.brightness = brightness;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused why this is here. When the backlight update_status() is called, the brightness in the props was already updated. This would just write the same value that is already there.

@Grimler91
Copy link
Author

Grimler91 commented Aug 14, 2023

@stephan-gh thanks for review/cleanup! Still works fine from some quick testing at least.

Will test it for a day or two and go through modifications.

Edit: some new dmesg errors during power on:

[  707.039921] msm_dsi 1a98000.dsi: [drm:dsi_cmds2buf_tx [msm]] *ERROR* wait for video done timed out
[  707.116441] msm_dsi 1a98000.dsi: [drm:dsi_cmds2buf_tx [msm]] *ERROR* wait for video done timed out
[  707.192995] msm_dsi 1a98000.dsi: [drm:dsi_cmds2buf_tx [msm]] *ERROR* wait for video done timed out
[ above happens 10 times ]
[  707.196728] [drm:mdp5_irq_error_handler [msm]] *ERROR* errors: 04000000

and when turning off the screen it goes to 100 % brightness for a short while.

@stephan-gh
Copy link
Member

stephan-gh commented Aug 19, 2023

[ above happens 10 times ]

That would be the brightness setting I guess (that's exactly 10 commands). Is this only with the MIPI_DSI_MODE_LPM change or also with my other changes?

@stephan-gh stephan-gh marked this pull request as draft September 1, 2023 16:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants