// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (c) 2019 Theobroma Systems Design und Consulting GmbH
*
* base on panel-kingdisplay-kd097d04.c
* Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd
*/
#include <linux/backlight.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regulator/consumer.h>
#include <video/mipi_display.h>
#include <drm/drm_crtc.h>
#include <drm/drm_device.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_modes.h>
#include <drm/drm_panel.h>
struct ltk500hd1829_cmd {
char cmd;
char data;
};
struct ltk500hd1829_desc {
const struct drm_display_mode *mode;
const struct ltk500hd1829_cmd *init;
unsigned int num_init;
};
struct ltk500hd1829 {
struct device *dev;
struct drm_panel panel;
struct gpio_desc *reset_gpio;
struct regulator *vcc;
struct regulator *iovcc;
const struct ltk500hd1829_desc *panel_desc;
};
static const struct ltk500hd1829_cmd ltk101b4029w_init[] = {
/* Page0 */
{ 0 xE0, 0 x00 },
/* PASSWORD */
{ 0 xE1, 0 x93 },
{ 0 xE2, 0 x65 },
{ 0 xE3, 0 xF8 },
{ 0 x80, 0 x03 }, /* 0X03:4-LANE; 0X02:3-LANE; 0X01:2-LANE */
/* Page1 */
{ 0 xE0, 0 x01 },
/* Set VCOM */
{ 0 x00, 0 x00 },
{ 0 x01, 0 x6F },
/* Set Gamma Power, VGMP,VGMN,VGSP,VGSN */
{ 0 x17, 0 x00 },
{ 0 x18, 0 xAF }, /* 4.3V */
{ 0 x19, 0 x01 }, /* 0.3V */
{ 0 x1A, 0 x00 },
{ 0 x1B, 0 xAF }, /* 4.3V */
{ 0 x1C, 0 x01 }, /* 0.3V */
/* Set Gate Power */
{ 0 x1F, 0 x3E }, /* VGH_R = 15V */
{ 0 x20, 0 x28 }, /* VGL_R = -12V */
{ 0 x21, 0 x28 }, /* VGL_R2 = -12V */
{ 0 x22, 0 x7E },
/* SETPANEL */
{ 0 x35, 0 x26 },
{ 0 x37, 0 x09 },
/* SET RGBCYC */
{ 0 x38, 0 x04 },
{ 0 x39, 0 x00 },
{ 0 x3A, 0 x01 },
{ 0 x3C, 0 x7C },
{ 0 x3D, 0 xFF },
{ 0 x3E, 0 xFF },
{ 0 x3F, 0 x7F },
/* Set TCON */
{ 0 x40, 0 x06 }, /* RSO = 800 RGB */
{ 0 x41, 0 xA0 }, /* LN = 640->1280 line */
{ 0 x42, 0 x81 },
{ 0 x43, 0 x08 }, /* VFP = 8 */
{ 0 x44, 0 x0B }, /* VBP = 12 */
{ 0 x45, 0 x28 }, /* HBP = 40 */
/* power voltage */
{ 0 x55, 0 x0F }, /* DCDCM = 0001, JD PWR_IC */
{ 0 x57, 0 x69 },
{ 0 x59, 0 x0A }, /* VCL = -2.9V */
{ 0 x5A, 0 x28 }, /* VGH = 15V */
{ 0 x5B, 0 x14 }, /* VGL = -11V */
/* Gamma */
{ 0 x5D, 0 x7C },
{ 0 x5E, 0 x65 },
{ 0 x5F, 0 x55 },
{ 0 x60, 0 x47 },
{ 0 x61, 0 x43 },
{ 0 x62, 0 x32 },
{ 0 x63, 0 x34 },
{ 0 x64, 0 x1C },
{ 0 x65, 0 x33 },
{ 0 x66, 0 x31 },
{ 0 x67, 0 x30 },
{ 0 x68, 0 x4E },
{ 0 x69, 0 x3C },
{ 0 x6A, 0 x44 },
{ 0 x6B, 0 x35 },
{ 0 x6C, 0 x31 },
{ 0 x6D, 0 x23 },
{ 0 x6E, 0 x11 },
{ 0 x6F, 0 x00 },
{ 0 x70, 0 x7C },
{ 0 x71, 0 x65 },
{ 0 x72, 0 x55 },
{ 0 x73, 0 x47 },
{ 0 x74, 0 x43 },
{ 0 x75, 0 x32 },
{ 0 x76, 0 x34 },
{ 0 x77, 0 x1C },
{ 0 x78, 0 x33 },
{ 0 x79, 0 x31 },
{ 0 x7A, 0 x30 },
{ 0 x7B, 0 x4E },
{ 0 x7C, 0 x3C },
{ 0 x7D, 0 x44 },
{ 0 x7E, 0 x35 },
{ 0 x7F, 0 x31 },
{ 0 x80, 0 x23 },
{ 0 x81, 0 x11 },
{ 0 x82, 0 x00 },
/* Page2, for GIP */
{ 0 xE0, 0 x02 },
/* GIP_L Pin mapping */
{ 0 x00, 0 x1E },
{ 0 x01, 0 x1E },
{ 0 x02, 0 x41 },
{ 0 x03, 0 x41 },
{ 0 x04, 0 x43 },
{ 0 x05, 0 x43 },
{ 0 x06, 0 x1F },
{ 0 x07, 0 x1F },
{ 0 x08, 0 x35 },
{ 0 x09, 0 x1F },
{ 0 x0A, 0 x15 },
{ 0 x0B, 0 x15 },
{ 0 x0C, 0 x1F },
{ 0 x0D, 0 x47 },
{ 0 x0E, 0 x47 },
{ 0 x0F, 0 x45 },
{ 0 x10, 0 x45 },
{ 0 x11, 0 x4B },
{ 0 x12, 0 x4B },
{ 0 x13, 0 x49 },
{ 0 x14, 0 x49 },
{ 0 x15, 0 x1F },
/* GIP_R Pin mapping */
{ 0 x16, 0 x1E },
{ 0 x17, 0 x1E },
{ 0 x18, 0 x40 },
{ 0 x19, 0 x40 },
{ 0 x1A, 0 x42 },
{ 0 x1B, 0 x42 },
{ 0 x1C, 0 x1F },
{ 0 x1D, 0 x1F },
{ 0 x1E, 0 x35 },
{ 0 x1F, 0 x1F },
{ 0 x20, 0 x15 },
{ 0 x21, 0 x15 },
{ 0 x22, 0 x1f },
{ 0 x23, 0 x46 },
{ 0 x24, 0 x46 },
{ 0 x25, 0 x44 },
{ 0 x26, 0 x44 },
{ 0 x27, 0 x4A },
{ 0 x28, 0 x4A },
{ 0 x29, 0 x48 },
{ 0 x2A, 0 x48 },
{ 0 x2B, 0 x1F },
/* GIP Timing */
{ 0 x58, 0 x40 },
{ 0 x5B, 0 x30 },
{ 0 x5C, 0 x03 },
{ 0 x5D, 0 x30 },
{ 0 x5E, 0 x01 },
{ 0 x5F, 0 x02 },
{ 0 x63, 0 x14 },
{ 0 x64, 0 x6A },
{ 0 x67, 0 x73 },
{ 0 x68, 0 x05 },
{ 0 x69, 0 x14 },
{ 0 x6A, 0 x6A },
{ 0 x6B, 0 x08 },
{ 0 x6C, 0 x00 },
{ 0 x6D, 0 x00 },
{ 0 x6E, 0 x00 },
{ 0 x6F, 0 x88 },
{ 0 x77, 0 xDD },
{ 0 x79, 0 x0E },
{ 0 x7A, 0 x03 },
{ 0 x7D, 0 x14 },
{ 0 x7E, 0 x6A },
/* Page4 */
{ 0 xE0, 0 x04 },
{ 0 x09, 0 x11 },
{ 0 x0E, 0 x48 },
{ 0 x2B, 0 x2B },
{ 0 x2D, 0 x03 },
{ 0 x2E, 0 x44 },
/* Page0 */
{ 0 xE0, 0 x00 },
{ 0 xE6, 0 x02 },
{ 0 xE7, 0 x0C },
};
static const struct drm_display_mode ltk101b4029w_mode = {
.hdisplay = 800 ,
.hsync_start = 800 + 18 ,
.hsync_end = 800 + 18 + 18 ,
.htotal = 800 + 18 + 18 + 18 ,
.vdisplay = 1280 ,
.vsync_start = 1280 + 24 ,
.vsync_end = 1280 + 24 + 4 ,
.vtotal = 1280 + 24 + 4 + 8 ,
.clock = 67330 ,
.width_mm = 136 ,
.height_mm = 218 ,
};
static const struct ltk500hd1829_desc ltk101b4029w_data = {
.mode = <k101b4029w_mode,
.init = ltk101b4029w_init,
.num_init = ARRAY_SIZE(ltk101b4029w_init),
};
/*
* There is no description in the Reference Manual about these commands.
* We received them from the vendor, so just use them as is.
*/
static const struct ltk500hd1829_cmd ltk500hd1829_init[] = {
{ 0 xE0, 0 x00 },
{ 0 xE1, 0 x93 },
{ 0 xE2, 0 x65 },
{ 0 xE3, 0 xF8 },
{ 0 x80, 0 x03 },
{ 0 xE0, 0 x04 },
{ 0 x2D, 0 x03 },
{ 0 xE0, 0 x01 },
{ 0 x00, 0 x00 },
{ 0 x01, 0 xB6 },
{ 0 x03, 0 x00 },
{ 0 x04, 0 xC5 },
{ 0 x17, 0 x00 },
{ 0 x18, 0 xBF },
{ 0 x19, 0 x01 },
{ 0 x1A, 0 x00 },
{ 0 x1B, 0 xBF },
{ 0 x1C, 0 x01 },
{ 0 x1F, 0 x7C },
{ 0 x20, 0 x26 },
{ 0 x21, 0 x26 },
{ 0 x22, 0 x4E },
{ 0 x37, 0 x09 },
{ 0 x38, 0 x04 },
{ 0 x39, 0 x08 },
{ 0 x3A, 0 x1F },
{ 0 x3B, 0 x1F },
{ 0 x3C, 0 x78 },
{ 0 x3D, 0 xFF },
{ 0 x3E, 0 xFF },
{ 0 x3F, 0 x00 },
{ 0 x40, 0 x04 },
{ 0 x41, 0 xA0 },
{ 0 x43, 0 x0F },
{ 0 x44, 0 x0A },
{ 0 x45, 0 x24 },
{ 0 x55, 0 x01 },
{ 0 x56, 0 x01 },
{ 0 x57, 0 xA5 },
{ 0 x58, 0 x0A },
{ 0 x59, 0 x4A },
{ 0 x5A, 0 x38 },
{ 0 x5B, 0 x10 },
{ 0 x5C, 0 x19 },
{ 0 x5D, 0 x7C },
{ 0 x5E, 0 x64 },
{ 0 x5F, 0 x54 },
{ 0 x60, 0 x48 },
{ 0 x61, 0 x44 },
{ 0 x62, 0 x35 },
{ 0 x63, 0 x3A },
{ 0 x64, 0 x24 },
{ 0 x65, 0 x3B },
{ 0 x66, 0 x39 },
{ 0 x67, 0 x37 },
{ 0 x68, 0 x56 },
{ 0 x69, 0 x41 },
{ 0 x6A, 0 x47 },
{ 0 x6B, 0 x2F },
{ 0 x6C, 0 x23 },
{ 0 x6D, 0 x13 },
{ 0 x6E, 0 x02 },
{ 0 x6F, 0 x08 },
{ 0 x70, 0 x7C },
{ 0 x71, 0 x64 },
{ 0 x72, 0 x54 },
{ 0 x73, 0 x48 },
{ 0 x74, 0 x44 },
{ 0 x75, 0 x35 },
{ 0 x76, 0 x3A },
{ 0 x77, 0 x22 },
{ 0 x78, 0 x3B },
{ 0 x79, 0 x39 },
{ 0 x7A, 0 x38 },
{ 0 x7B, 0 x52 },
{ 0 x7C, 0 x41 },
{ 0 x7D, 0 x47 },
{ 0 x7E, 0 x2F },
{ 0 x7F, 0 x23 },
{ 0 x80, 0 x13 },
{ 0 x81, 0 x02 },
{ 0 x82, 0 x08 },
{ 0 xE0, 0 x02 },
{ 0 x00, 0 x57 },
{ 0 x01, 0 x77 },
{ 0 x02, 0 x44 },
{ 0 x03, 0 x46 },
{ 0 x04, 0 x48 },
{ 0 x05, 0 x4A },
{ 0 x06, 0 x4C },
{ 0 x07, 0 x4E },
{ 0 x08, 0 x50 },
{ 0 x09, 0 x55 },
{ 0 x0A, 0 x52 },
{ 0 x0B, 0 x55 },
{ 0 x0C, 0 x55 },
{ 0 x0D, 0 x55 },
{ 0 x0E, 0 x55 },
{ 0 x0F, 0 x55 },
{ 0 x10, 0 x55 },
{ 0 x11, 0 x55 },
{ 0 x12, 0 x55 },
{ 0 x13, 0 x40 },
{ 0 x14, 0 x55 },
{ 0 x15, 0 x55 },
{ 0 x16, 0 x57 },
{ 0 x17, 0 x77 },
{ 0 x18, 0 x45 },
{ 0 x19, 0 x47 },
{ 0 x1A, 0 x49 },
{ 0 x1B, 0 x4B },
{ 0 x1C, 0 x4D },
{ 0 x1D, 0 x4F },
{ 0 x1E, 0 x51 },
{ 0 x1F, 0 x55 },
{ 0 x20, 0 x53 },
{ 0 x21, 0 x55 },
{ 0 x22, 0 x55 },
{ 0 x23, 0 x55 },
{ 0 x24, 0 x55 },
{ 0 x25, 0 x55 },
{ 0 x26, 0 x55 },
{ 0 x27, 0 x55 },
{ 0 x28, 0 x55 },
{ 0 x29, 0 x41 },
{ 0 x2A, 0 x55 },
{ 0 x2B, 0 x55 },
{ 0 x2C, 0 x57 },
{ 0 x2D, 0 x77 },
{ 0 x2E, 0 x4F },
{ 0 x2F, 0 x4D },
{ 0 x30, 0 x4B },
{ 0 x31, 0 x49 },
{ 0 x32, 0 x47 },
{ 0 x33, 0 x45 },
{ 0 x34, 0 x41 },
{ 0 x35, 0 x55 },
{ 0 x36, 0 x53 },
{ 0 x37, 0 x55 },
{ 0 x38, 0 x55 },
{ 0 x39, 0 x55 },
{ 0 x3A, 0 x55 },
{ 0 x3B, 0 x55 },
{ 0 x3C, 0 x55 },
{ 0 x3D, 0 x55 },
{ 0 x3E, 0 x55 },
{ 0 x3F, 0 x51 },
{ 0 x40, 0 x55 },
{ 0 x41, 0 x55 },
{ 0 x42, 0 x57 },
{ 0 x43, 0 x77 },
{ 0 x44, 0 x4E },
{ 0 x45, 0 x4C },
{ 0 x46, 0 x4A },
{ 0 x47, 0 x48 },
{ 0 x48, 0 x46 },
{ 0 x49, 0 x44 },
{ 0 x4A, 0 x40 },
{ 0 x4B, 0 x55 },
{ 0 x4C, 0 x52 },
{ 0 x4D, 0 x55 },
{ 0 x4E, 0 x55 },
{ 0 x4F, 0 x55 },
{ 0 x50, 0 x55 },
{ 0 x51, 0 x55 },
{ 0 x52, 0 x55 },
{ 0 x53, 0 x55 },
{ 0 x54, 0 x55 },
{ 0 x55, 0 x50 },
{ 0 x56, 0 x55 },
{ 0 x57, 0 x55 },
{ 0 x58, 0 x40 },
{ 0 x59, 0 x00 },
{ 0 x5A, 0 x00 },
{ 0 x5B, 0 x10 },
{ 0 x5C, 0 x09 },
{ 0 x5D, 0 x30 },
{ 0 x5E, 0 x01 },
{ 0 x5F, 0 x02 },
{ 0 x60, 0 x30 },
{ 0 x61, 0 x03 },
{ 0 x62, 0 x04 },
{ 0 x63, 0 x06 },
{ 0 x64, 0 x6A },
{ 0 x65, 0 x75 },
{ 0 x66, 0 x0F },
{ 0 x67, 0 xB3 },
{ 0 x68, 0 x0B },
{ 0 x69, 0 x06 },
{ 0 x6A, 0 x6A },
{ 0 x6B, 0 x10 },
{ 0 x6C, 0 x00 },
{ 0 x6D, 0 x04 },
{ 0 x6E, 0 x04 },
{ 0 x6F, 0 x88 },
{ 0 x70, 0 x00 },
{ 0 x71, 0 x00 },
{ 0 x72, 0 x06 },
{ 0 x73, 0 x7B },
{ 0 x74, 0 x00 },
{ 0 x75, 0 xBC },
{ 0 x76, 0 x00 },
{ 0 x77, 0 x05 },
{ 0 x78, 0 x2E },
{ 0 x79, 0 x00 },
{ 0 x7A, 0 x00 },
{ 0 x7B, 0 x00 },
{ 0 x7C, 0 x00 },
{ 0 x7D, 0 x03 },
{ 0 x7E, 0 x7B },
{ 0 xE0, 0 x04 },
{ 0 x09, 0 x10 },
{ 0 x2B, 0 x2B },
{ 0 x2E, 0 x44 },
{ 0 xE0, 0 x00 },
{ 0 xE6, 0 x02 },
{ 0 xE7, 0 x02 },
{ 0 x35, 0 x00 },
};
static const struct drm_display_mode ltk500hd1829_mode = {
.hdisplay = 720 ,
.hsync_start = 720 + 50 ,
.hsync_end = 720 + 50 + 50 ,
.htotal = 720 + 50 + 50 + 50 ,
.vdisplay = 1280 ,
.vsync_start = 1280 + 30 ,
.vsync_end = 1280 + 30 + 4 ,
.vtotal = 1280 + 30 + 4 + 12 ,
.clock = 69217 ,
.width_mm = 62 ,
.height_mm = 110 ,
};
static const struct ltk500hd1829_desc ltk500hd1829_data = {
.mode = <k500hd1829_mode,
.init = ltk500hd1829_init,
.num_init = ARRAY_SIZE(ltk500hd1829_init),
};
static inline
struct ltk500hd1829 *panel_to_ltk500hd1829(struct drm_panel *panel)
{
return container_of(panel, struct ltk500hd1829, panel);
}
static int ltk500hd1829_unprepare(struct drm_panel *panel)
{
struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
int ret;
ret = mipi_dsi_dcs_set_display_off(dsi);
if (ret < 0 )
dev_err(panel->dev, "failed to set display off: %d\n" , ret);
ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
if (ret < 0 ) {
dev_err(panel->dev, "failed to enter sleep mode: %d\n" , ret);
}
/* 120ms to enter sleep mode */
msleep(120 );
regulator_disable(ctx->iovcc);
regulator_disable(ctx->vcc);
return 0 ;
}
static int ltk500hd1829_prepare(struct drm_panel *panel)
{
struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel);
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
unsigned int i;
int ret;
ret = regulator_enable(ctx->vcc);
if (ret < 0 ) {
dev_err(ctx->dev, "Failed to enable vci supply: %d\n" , ret);
return ret;
}
ret = regulator_enable(ctx->iovcc);
if (ret < 0 ) {
dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n" , ret);
goto disable_vcc;
}
gpiod_set_value_cansleep(ctx->reset_gpio, 1 );
/* tRW: 10us */
usleep_range(10 , 20 );
gpiod_set_value_cansleep(ctx->reset_gpio, 0 );
/* tRT: >= 5ms */
usleep_range(5000 , 6000 );
for (i = 0 ; i < ctx->panel_desc->num_init; i++) {
ret = mipi_dsi_generic_write(dsi, &ctx->panel_desc->init[i],
sizeof (struct ltk500hd1829_cmd));
if (ret < 0 ) {
dev_err(panel->dev, "failed to write init cmds: %d\n" , ret);
goto disable_iovcc;
}
}
ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
if (ret < 0 ) {
dev_err(panel->dev, "failed to exit sleep mode: %d\n" , ret);
goto disable_iovcc;
}
/* 120ms to exit sleep mode */
msleep(120 );
ret = mipi_dsi_dcs_set_display_on(dsi);
if (ret < 0 ) {
dev_err(panel->dev, "failed to set display on: %d\n" , ret);
goto disable_iovcc;
}
return 0 ;
disable_iovcc:
regulator_disable(ctx->iovcc);
disable_vcc:
regulator_disable(ctx->vcc);
return ret;
}
static int ltk500hd1829_get_modes(struct drm_panel *panel,
struct drm_connector *connector)
{
struct ltk500hd1829 *ctx = panel_to_ltk500hd1829(panel);
struct drm_display_mode *mode;
mode = drm_mode_duplicate(connector->dev, ctx->panel_desc->mode);
if (!mode) {
dev_err(ctx->dev, "failed to add mode %ux%u@%u\n" ,
ctx->panel_desc->mode->hdisplay, ctx->panel_desc->mode->vdisplay,
drm_mode_vrefresh(ctx->panel_desc->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 ltk500hd1829_funcs = {
.unprepare = ltk500hd1829_unprepare,
.prepare = ltk500hd1829_prepare,
.get_modes = ltk500hd1829_get_modes,
};
static int ltk500hd1829_probe(struct mipi_dsi_device *dsi)
{
struct ltk500hd1829 *ctx;
struct device *dev = &dsi->dev;
int ret;
ctx = devm_drm_panel_alloc(dev, struct ltk500hd1829, panel,
<k500hd1829_funcs,
DRM_MODE_CONNECTOR_DSI);
if (IS_ERR(ctx))
return PTR_ERR(ctx);
ctx->panel_desc = of_device_get_match_data(dev);
if (!ctx->panel_desc)
return -EINVAL;
ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset" , GPIOD_OUT_LOW);
if (IS_ERR(ctx->reset_gpio)) {
dev_err(dev, "cannot get reset gpio\n" );
return PTR_ERR(ctx->reset_gpio);
}
ctx->vcc = devm_regulator_get(dev, "vcc" );
if (IS_ERR(ctx->vcc)) {
ret = PTR_ERR(ctx->vcc);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to request vcc regulator: %d\n" , ret);
return ret;
}
ctx->iovcc = devm_regulator_get(dev, "iovcc" );
if (IS_ERR(ctx->iovcc)) {
ret = PTR_ERR(ctx->iovcc);
if (ret != -EPROBE_DEFER)
dev_err(dev, "Failed to request iovcc regulator: %d\n" , ret);
return ret;
}
mipi_dsi_set_drvdata(dsi, ctx);
ctx->dev = dev;
dsi->lanes = 4 ;
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
ret = drm_panel_of_backlight(&ctx->panel);
if (ret)
return ret;
drm_panel_add(&ctx->panel);
ret = mipi_dsi_attach(dsi);
if (ret < 0 ) {
dev_err(dev, "mipi_dsi_attach failed: %d\n" , ret);
drm_panel_remove(&ctx->panel);
return ret;
}
return 0 ;
}
static void ltk500hd1829_remove(struct mipi_dsi_device *dsi)
{
struct ltk500hd1829 *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 ltk500hd1829_of_match[] = {
{
.compatible = "leadtek,ltk101b4029w" ,
.data = <k101b4029w_data,
},
{
.compatible = "leadtek,ltk500hd1829" ,
.data = <k500hd1829_data,
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, ltk500hd1829_of_match);
static struct mipi_dsi_driver ltk500hd1829_driver = {
.driver = {
.name = "panel-leadtek-ltk500hd1829" ,
.of_match_table = ltk500hd1829_of_match,
},
.probe = ltk500hd1829_probe,
.remove = ltk500hd1829_remove,
};
module_mipi_dsi_driver(ltk500hd1829_driver);
MODULE_AUTHOR("Heiko Stuebner <heiko.stuebner@theobroma-systems.com>" );
MODULE_DESCRIPTION("Leadtek LTK500HD1829 panel driver" );
MODULE_LICENSE("GPL v2" );
Messung V0.5 in Prozent C=94 H=98 G=95
¤ Dauer der Verarbeitung: 0.12 Sekunden
(vorverarbeitet am 2026-06-05)
¤
*© Formatika GbR, Deutschland