drm/panel: novatek-nt35560: Clean up driver

Update driver to use the "multi" variants of MIPI functions which
facilitate improved error handling and cleaner driver code.

Remove information from a comment which was made obsolete by commit
994ea402c7 ("drm/panel: Rename Sony ACX424 to Novatek NT35560"), which
determined that this driver supports the Novatek NT35560 panel
controller.

Reviewed-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Brigham Campbell <me@brighamcampbell.com>
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Link: https://lore.kernel.org/r/20250731032343.1258366-4-me@brighamcampbell.com
This commit is contained in:
Brigham Campbell 2025-07-30 21:23:43 -06:00 committed by Douglas Anderson
parent ffc23a204a
commit 5fbc0dbb92

View File

@ -148,24 +148,20 @@ static inline struct nt35560 *panel_to_nt35560(struct drm_panel *panel)
static int nt35560_set_brightness(struct backlight_device *bl) static int nt35560_set_brightness(struct backlight_device *bl)
{ {
struct nt35560 *nt = bl_get_data(bl); struct nt35560 *nt = bl_get_data(bl);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); struct mipi_dsi_multi_context dsi_ctx = {
int period_ns = 1023; .dsi = to_mipi_dsi_device(nt->dev)
};
int duty_ns = bl->props.brightness; int duty_ns = bl->props.brightness;
int period_ns = 1023;
u8 pwm_ratio; u8 pwm_ratio;
u8 pwm_div; u8 pwm_div;
u8 par;
int ret;
if (backlight_is_blank(bl)) { if (backlight_is_blank(bl)) {
/* Disable backlight */ /* Disable backlight */
par = 0x00; mipi_dsi_dcs_write_seq_multi(&dsi_ctx,
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, MIPI_DCS_WRITE_CONTROL_DISPLAY,
&par, 1); 0x00);
if (ret < 0) { return dsi_ctx.accum_err;
dev_err(nt->dev, "failed to disable display backlight (%d)\n", ret);
return ret;
}
return 0;
} }
/* Calculate the PWM duty cycle in n/256's */ /* Calculate the PWM duty cycle in n/256's */
@ -176,12 +172,6 @@ static int nt35560_set_brightness(struct backlight_device *bl)
/* Set up PWM dutycycle ONE byte (differs from the standard) */ /* Set up PWM dutycycle ONE byte (differs from the standard) */
dev_dbg(nt->dev, "calculated duty cycle %02x\n", pwm_ratio); dev_dbg(nt->dev, "calculated duty cycle %02x\n", pwm_ratio);
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
&pwm_ratio, 1);
if (ret < 0) {
dev_err(nt->dev, "failed to set display PWM ratio (%d)\n", ret);
return ret;
}
/* /*
* Sequence to write PWMDIV: * Sequence to write PWMDIV:
@ -192,46 +182,23 @@ static int nt35560_set_brightness(struct backlight_device *bl)
* 0x22 PWMDIV * 0x22 PWMDIV
* 0x7F 0xAA CMD2 page 1 lock * 0x7F 0xAA CMD2 page 1 lock
*/ */
par = 0xaa; mipi_dsi_dcs_write_var_seq_multi(&dsi_ctx,
ret = mipi_dsi_dcs_write(dsi, 0xf3, &par, 1); MIPI_DCS_SET_DISPLAY_BRIGHTNESS,
if (ret < 0) { pwm_ratio);
dev_err(nt->dev, "failed to unlock CMD 2 (%d)\n", ret);
return ret; mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0xaa);
} mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0x01);
par = 0x01; mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7d, 0x01);
ret = mipi_dsi_dcs_write(dsi, 0x00, &par, 1);
if (ret < 0) { mipi_dsi_dcs_write_var_seq_multi(&dsi_ctx, 0x22, pwm_div);
dev_err(nt->dev, "failed to enter page 1 (%d)\n", ret);
return ret; mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x7f, 0xaa);
}
par = 0x01;
ret = mipi_dsi_dcs_write(dsi, 0x7d, &par, 1);
if (ret < 0) {
dev_err(nt->dev, "failed to disable MTP reload (%d)\n", ret);
return ret;
}
ret = mipi_dsi_dcs_write(dsi, 0x22, &pwm_div, 1);
if (ret < 0) {
dev_err(nt->dev, "failed to set PWM divisor (%d)\n", ret);
return ret;
}
par = 0xaa;
ret = mipi_dsi_dcs_write(dsi, 0x7f, &par, 1);
if (ret < 0) {
dev_err(nt->dev, "failed to lock CMD 2 (%d)\n", ret);
return ret;
}
/* Enable backlight */ /* Enable backlight */
par = 0x24; mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY,
ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
&par, 1);
if (ret < 0) {
dev_err(nt->dev, "failed to enable display backlight (%d)\n", ret);
return ret;
}
return 0; return dsi_ctx.accum_err;
} }
static const struct backlight_ops nt35560_bl_ops = { static const struct backlight_ops nt35560_bl_ops = {
@ -244,32 +211,23 @@ static const struct backlight_properties nt35560_bl_props = {
.max_brightness = 1023, .max_brightness = 1023,
}; };
static int nt35560_read_id(struct nt35560 *nt) static void nt35560_read_id(struct mipi_dsi_multi_context *dsi_ctx)
{ {
struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); struct device dev = dsi_ctx->dsi->dev;
u8 vendor, version, panel; u8 vendor, version, panel;
u16 val; u16 val;
int ret;
ret = mipi_dsi_dcs_read(dsi, NT35560_DCS_READ_ID1, &vendor, 1); mipi_dsi_dcs_read_multi(dsi_ctx, NT35560_DCS_READ_ID1, &vendor, 1);
if (ret < 0) { mipi_dsi_dcs_read_multi(dsi_ctx, NT35560_DCS_READ_ID2, &version, 1);
dev_err(nt->dev, "could not vendor ID byte\n"); mipi_dsi_dcs_read_multi(dsi_ctx, NT35560_DCS_READ_ID3, &panel, 1);
return ret;
} if (dsi_ctx->accum_err < 0)
ret = mipi_dsi_dcs_read(dsi, NT35560_DCS_READ_ID2, &version, 1); return;
if (ret < 0) {
dev_err(nt->dev, "could not read device version byte\n");
return ret;
}
ret = mipi_dsi_dcs_read(dsi, NT35560_DCS_READ_ID3, &panel, 1);
if (ret < 0) {
dev_err(nt->dev, "could not read panel ID byte\n");
return ret;
}
if (vendor == 0x00) { if (vendor == 0x00) {
dev_err(nt->dev, "device vendor ID is zero\n"); dev_err(&dev, "device vendor ID is zero\n");
return -ENODEV; dsi_ctx->accum_err = -ENODEV;
return;
} }
val = (vendor << 8) | panel; val = (vendor << 8) | panel;
@ -278,16 +236,16 @@ static int nt35560_read_id(struct nt35560 *nt)
case DISPLAY_SONY_ACX424AKP_ID2: case DISPLAY_SONY_ACX424AKP_ID2:
case DISPLAY_SONY_ACX424AKP_ID3: case DISPLAY_SONY_ACX424AKP_ID3:
case DISPLAY_SONY_ACX424AKP_ID4: case DISPLAY_SONY_ACX424AKP_ID4:
dev_info(nt->dev, "MTP vendor: %02x, version: %02x, panel: %02x\n", dev_info(&dev,
"MTP vendor: %02x, version: %02x, panel: %02x\n",
vendor, version, panel); vendor, version, panel);
break; break;
default: default:
dev_info(nt->dev, "unknown vendor: %02x, version: %02x, panel: %02x\n", dev_info(&dev,
"unknown vendor: %02x, version: %02x, panel: %02x\n",
vendor, version, panel); vendor, version, panel);
break; break;
} }
return 0;
} }
static int nt35560_power_on(struct nt35560 *nt) static int nt35560_power_on(struct nt35560 *nt)
@ -322,92 +280,56 @@ static void nt35560_power_off(struct nt35560 *nt)
static int nt35560_prepare(struct drm_panel *panel) static int nt35560_prepare(struct drm_panel *panel)
{ {
struct nt35560 *nt = panel_to_nt35560(panel); struct nt35560 *nt = panel_to_nt35560(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); struct mipi_dsi_multi_context dsi_ctx = {
const u8 mddi = 3; .dsi = to_mipi_dsi_device(nt->dev)
};
int ret; int ret;
ret = nt35560_power_on(nt); ret = nt35560_power_on(nt);
if (ret) if (ret)
return ret; return ret;
ret = nt35560_read_id(nt); nt35560_read_id(&dsi_ctx);
if (ret) {
dev_err(nt->dev, "failed to read panel ID (%d)\n", ret);
goto err_power_off;
}
/* Enabe tearing mode: send TE (tearing effect) at VBLANK */ /* Enable tearing mode: send TE (tearing effect) at VBLANK */
ret = mipi_dsi_dcs_set_tear_on(dsi, mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx,
MIPI_DSI_DCS_TEAR_MODE_VBLANK); MIPI_DSI_DCS_TEAR_MODE_VBLANK);
if (ret) {
dev_err(nt->dev, "failed to enable vblank TE (%d)\n", ret);
goto err_power_off;
}
/* /*
* Set MDDI * Set MDDI
* *
* This presumably deactivates the Qualcomm MDDI interface and * This presumably deactivates the Qualcomm MDDI interface and
* selects DSI, similar code is found in other drivers such as the * selects DSI, similar code is found in other drivers such as the
* Sharp LS043T1LE01 which makes us suspect that this panel may be * Sharp LS043T1LE01.
* using a Novatek NT35565 or similar display driver chip that shares
* this command. Due to the lack of documentation we cannot know for
* sure.
*/ */
ret = mipi_dsi_dcs_write(dsi, NT35560_DCS_SET_MDDI, mipi_dsi_dcs_write_seq_multi(&dsi_ctx, NT35560_DCS_SET_MDDI, 3);
&mddi, sizeof(mddi));
if (ret < 0) {
dev_err(nt->dev, "failed to set MDDI (%d)\n", ret);
goto err_power_off;
}
/* Exit sleep mode */ mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
ret = mipi_dsi_dcs_exit_sleep_mode(dsi); mipi_dsi_msleep(&dsi_ctx, 140);
if (ret) {
dev_err(nt->dev, "failed to exit sleep mode (%d)\n", ret);
goto err_power_off;
}
msleep(140);
ret = mipi_dsi_dcs_set_display_on(dsi); mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
if (ret) {
dev_err(nt->dev, "failed to turn display on (%d)\n", ret);
goto err_power_off;
}
if (nt->video_mode) { if (nt->video_mode) {
/* In video mode turn peripheral on */ mipi_dsi_turn_on_peripheral_multi(&dsi_ctx);
ret = mipi_dsi_turn_on_peripheral(dsi);
if (ret) {
dev_err(nt->dev, "failed to turn on peripheral\n");
goto err_power_off;
}
} }
return 0; if (dsi_ctx.accum_err < 0)
err_power_off:
nt35560_power_off(nt); nt35560_power_off(nt);
return ret; return dsi_ctx.accum_err;
} }
static int nt35560_unprepare(struct drm_panel *panel) static int nt35560_unprepare(struct drm_panel *panel)
{ {
struct nt35560 *nt = panel_to_nt35560(panel); struct nt35560 *nt = panel_to_nt35560(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(nt->dev); struct mipi_dsi_multi_context dsi_ctx = {
int ret; .dsi = to_mipi_dsi_device(nt->dev)
};
ret = mipi_dsi_dcs_set_display_off(dsi); mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
if (ret) { mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
dev_err(nt->dev, "failed to turn display off (%d)\n", ret);
return ret; if (dsi_ctx.accum_err < 0)
} return dsi_ctx.accum_err;
/* Enter sleep mode */
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret) {
dev_err(nt->dev, "failed to enter sleep mode (%d)\n", ret);
return ret;
}
msleep(85); msleep(85);
nt35560_power_off(nt); nt35560_power_off(nt);