diff --git a/drivers/gpu/drm/solomon/ssd130x.c b/drivers/gpu/drm/solomon/ssd130x.c index 0940eae7a2e4..f49e5245b216 100644 --- a/drivers/gpu/drm/solomon/ssd130x.c +++ b/drivers/gpu/drm/solomon/ssd130x.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -140,6 +141,11 @@ #define SSD133X_SET_PRECHARGE_VOLTAGE 0xbb #define SSD133X_SET_VCOMH_VOLTAGE 0xbe +/* ssd133x A/B/C channel contrast at full brightness (white balance) */ +#define SSD133X_DEFAULT_CONTRAST_A 0x91 +#define SSD133X_DEFAULT_CONTRAST_B 0x50 +#define SSD133X_DEFAULT_CONTRAST_C 0x7d + #define MAX_CONTRAST 255 const struct ssd130x_deviceinfo ssd130x_variants[] = { @@ -582,12 +588,37 @@ static int ssd132x_init(struct ssd130x_device *ssd130x) return ssd130x_run_cmd_seq(ssd130x, cmds); } -static int ssd133x_init(struct ssd130x_device *ssd130x) +/* Scale a channel's white-balance calibration contrast by the requested brightness */ +static u8 ssd130x_scale_contrast(u8 calibration, u32 brightness) +{ + return DIV_ROUND_CLOSEST(calibration * brightness, MAX_CONTRAST); +} + +/* + * The A/B/C contrast channels drive sub-pixels whose OLED materials differ + * in luminous efficiency, so the per-channel values are a white-balance + * calibration. Scale them by the requested brightness instead of + * overwriting them, to keep the white point while dimming. + */ +static int ssd133x_set_contrast(struct ssd130x_device *ssd130x, u32 brightness) { const u8 cmds[] = { - 2, SSD133X_CONTRAST_A, 0x91, - 2, SSD133X_CONTRAST_B, 0x50, - 2, SSD133X_CONTRAST_C, 0x7d, + 2, SSD133X_CONTRAST_A, + ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_A, brightness), + 2, SSD133X_CONTRAST_B, + ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_B, brightness), + 2, SSD133X_CONTRAST_C, + ssd130x_scale_contrast(SSD133X_DEFAULT_CONTRAST_C, brightness), + 0, + }; + + return ssd130x_run_cmd_seq(ssd130x, cmds); +} + +static int ssd133x_init(struct ssd130x_device *ssd130x) +{ + int ret; + const u8 cmds[] = { 2, SSD133X_SET_MASTER_CURRENT, 0x06, 3, SSD133X_SET_COL_RANGE, 0x00, ssd130x->width - 1, 3, SSD133X_SET_ROW_RANGE, 0x00, ssd130x->height - 1, @@ -614,6 +645,10 @@ static int ssd133x_init(struct ssd130x_device *ssd130x) 0, }; + ret = ssd133x_set_contrast(ssd130x, ssd130x->contrast); + if (ret < 0) + return ret; + return ssd130x_run_cmd_seq(ssd130x, cmds); }