Add Densitron DMT050WVNMCMI-1A to ILI9806E DSI Add i2c-frag to allow probe deferral until Goodix touchpanel chip in the display is initialized. Make reset-gpios optional to allow delegation of reset to Goodix driver.
Signed-off-by: Bart Steinmayr <[email protected]> --- drivers/gpu/drm/panel/panel-ilitek-ili9806e.c | 202 +++++++++++++++++- 1 file changed, 201 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c index 18aa6222b0c5..ce77ee7cbc10 100644 --- a/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c +++ b/drivers/gpu/drm/panel/panel-ilitek-ili9806e.c @@ -10,6 +10,9 @@ #include <linux/module.h> #include <linux/property.h> #include <linux/regulator/consumer.h> +#include <linux/of.h> + +#include <linux/i2c.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_modes.h> @@ -166,6 +169,22 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) struct ili9806e_panel *ctx; int i, ret; + struct device_node *i2c_frag = of_parse_phandle(dev->of_node, "i2c-frag", 0); + + if (i2c_frag) { + void *i2c_driver_data = NULL; + + struct i2c_client *i2c_frag_client = of_find_i2c_device_by_node(i2c_frag); + + of_node_put(i2c_frag); + if (i2c_frag_client) { + i2c_driver_data = dev_get_drvdata(&i2c_frag_client->dev); + put_device(&i2c_frag_client->dev); + } + if (!i2c_driver_data) + return dev_err_probe(dev, -EPROBE_DEFER, "failed to get i2c-frag\n"); + } + ctx = devm_drm_panel_alloc(dev, struct ili9806e_panel, panel, &ili9806e_funcs, DRM_MODE_CONNECTOR_DSI); if (IS_ERR(ctx)) @@ -181,7 +200,7 @@ static int ili9806e_dsi_probe(struct mipi_dsi_device *dsi) if (ret < 0) return ret; - ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); + ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset-gpios\n"); @@ -542,8 +561,188 @@ static const struct panel_desc dmt028vghmcmi_1d_desc = { .lanes = 2, }; +static u8 dsi_read(struct mipi_dsi_multi_context *ctx, u8 command) +{ + struct mipi_dsi_device *dsi = ctx->dsi; + + u8 len = 1; + u8 result_data = 0xFF; + + mipi_dsi_set_maximum_return_packet_size(dsi, 1); + mipi_dsi_dcs_read(dsi, command, &result_data, len); + + return result_data; +} + +static void dmt050wvnmcmi_1a_init(struct mipi_dsi_multi_context *ctx) +{ + // Try to read pixel format to check display connection + u8 pixel_format = dsi_read(ctx, 0x0c); + + if (pixel_format != 0x70) + dev_err(&ctx->dsi->dev, "Read pixel format failed: %d\n", pixel_format); + + mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x08, 0x10); + mipi_dsi_dcs_write_seq_multi(ctx, 0x20, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x30, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x31, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x40, 0x16); + mipi_dsi_dcs_write_seq_multi(ctx, 0x41, 0x33); + mipi_dsi_dcs_write_seq_multi(ctx, 0x42, 0x03); + mipi_dsi_dcs_write_seq_multi(ctx, 0x43, 0x09); + mipi_dsi_dcs_write_seq_multi(ctx, 0x44, 0x06); + mipi_dsi_dcs_write_seq_multi(ctx, 0x50, 0x88); + mipi_dsi_dcs_write_seq_multi(ctx, 0x51, 0x88); + mipi_dsi_dcs_write_seq_multi(ctx, 0x52, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x53, 0x49); + mipi_dsi_dcs_write_seq_multi(ctx, 0x55, 0x49); + mipi_dsi_dcs_write_seq_multi(ctx, 0x60, 0x07); + mipi_dsi_dcs_write_seq_multi(ctx, 0x61, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x62, 0x07); + mipi_dsi_dcs_write_seq_multi(ctx, 0x63, 0x00); + + //Positive Gamma + mipi_dsi_dcs_write_seq_multi(ctx, 0xA0, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA1, 0x09); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA2, 0x11); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA3, 0x0B); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA4, 0x05); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA5, 0x08); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA6, 0x06); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA7, 0x04); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA8, 0x09); + mipi_dsi_dcs_write_seq_multi(ctx, 0xA9, 0x0C); + mipi_dsi_dcs_write_seq_multi(ctx, 0xAA, 0x15); + mipi_dsi_dcs_write_seq_multi(ctx, 0xAB, 0x08); + mipi_dsi_dcs_write_seq_multi(ctx, 0xAC, 0x0F); + mipi_dsi_dcs_write_seq_multi(ctx, 0xAD, 0x12); + mipi_dsi_dcs_write_seq_multi(ctx, 0xAE, 0x09); + mipi_dsi_dcs_write_seq_multi(ctx, 0xAF, 0x00); + + //Negative Gamma + mipi_dsi_dcs_write_seq_multi(ctx, 0xC0, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC1, 0x09); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC2, 0x10); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC3, 0x0C); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC4, 0x05); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC5, 0x08); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC6, 0x06); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC7, 0x04); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC8, 0x08); + mipi_dsi_dcs_write_seq_multi(ctx, 0xC9, 0x0C); + mipi_dsi_dcs_write_seq_multi(ctx, 0xCA, 0x14); + mipi_dsi_dcs_write_seq_multi(ctx, 0xCB, 0x08); + mipi_dsi_dcs_write_seq_multi(ctx, 0xCC, 0x0F); + mipi_dsi_dcs_write_seq_multi(ctx, 0xCD, 0x11); + mipi_dsi_dcs_write_seq_multi(ctx, 0xCE, 0x09); + mipi_dsi_dcs_write_seq_multi(ctx, 0xCF, 0x00); + + mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x6); + + mipi_dsi_dcs_write_seq_multi(ctx, 0x00, 0x20); + mipi_dsi_dcs_write_seq_multi(ctx, 0x01, 0x0A); + mipi_dsi_dcs_write_seq_multi(ctx, 0x02, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x03, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x04, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x05, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x06, 0x98); + mipi_dsi_dcs_write_seq_multi(ctx, 0x07, 0x06); + mipi_dsi_dcs_write_seq_multi(ctx, 0x08, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x09, 0x80); + mipi_dsi_dcs_write_seq_multi(ctx, 0x0A, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x0B, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x0C, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x0D, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x0E, 0x05); + mipi_dsi_dcs_write_seq_multi(ctx, 0x0F, 0x00); + + mipi_dsi_dcs_write_seq_multi(ctx, 0x10, 0xF0); + mipi_dsi_dcs_write_seq_multi(ctx, 0x11, 0xF4); + mipi_dsi_dcs_write_seq_multi(ctx, 0x12, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x13, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x14, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x15, 0xC0); + mipi_dsi_dcs_write_seq_multi(ctx, 0x16, 0x08); + mipi_dsi_dcs_write_seq_multi(ctx, 0x17, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x18, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x19, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x1A, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x1B, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x1C, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x1D, 0x00); + + mipi_dsi_dcs_write_seq_multi(ctx, 0x20, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x21, 0x23); + mipi_dsi_dcs_write_seq_multi(ctx, 0x22, 0x45); + mipi_dsi_dcs_write_seq_multi(ctx, 0x23, 0x67); + mipi_dsi_dcs_write_seq_multi(ctx, 0x24, 0x01); + mipi_dsi_dcs_write_seq_multi(ctx, 0x25, 0x23); + mipi_dsi_dcs_write_seq_multi(ctx, 0x26, 0x45); + mipi_dsi_dcs_write_seq_multi(ctx, 0x27, 0x67); + + mipi_dsi_dcs_write_seq_multi(ctx, 0x30, 0x11); + mipi_dsi_dcs_write_seq_multi(ctx, 0x31, 0x11); + mipi_dsi_dcs_write_seq_multi(ctx, 0x32, 0x00); + mipi_dsi_dcs_write_seq_multi(ctx, 0x33, 0xEE); + mipi_dsi_dcs_write_seq_multi(ctx, 0x34, 0xFF); + mipi_dsi_dcs_write_seq_multi(ctx, 0x35, 0xBB); + mipi_dsi_dcs_write_seq_multi(ctx, 0x36, 0xAA); + mipi_dsi_dcs_write_seq_multi(ctx, 0x37, 0xDD); + mipi_dsi_dcs_write_seq_multi(ctx, 0x38, 0xCC); + mipi_dsi_dcs_write_seq_multi(ctx, 0x39, 0x66); + mipi_dsi_dcs_write_seq_multi(ctx, 0x3A, 0x77); + mipi_dsi_dcs_write_seq_multi(ctx, 0x3B, 0x22); + mipi_dsi_dcs_write_seq_multi(ctx, 0x3C, 0x22); + mipi_dsi_dcs_write_seq_multi(ctx, 0x3D, 0x22); + mipi_dsi_dcs_write_seq_multi(ctx, 0x3E, 0x22); + mipi_dsi_dcs_write_seq_multi(ctx, 0x3F, 0x22); + mipi_dsi_dcs_write_seq_multi(ctx, 0x40, 0x22); + + mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x07); + + mipi_dsi_dcs_write_seq_multi(ctx, 0x17, 0x22); + mipi_dsi_dcs_write_seq_multi(ctx, 0x02, 0x77); + mipi_dsi_dcs_write_seq_multi(ctx, 0x26, 0xB2); + + mipi_dsi_dcs_write_seq_multi(ctx, 0xff, 0xff, 0x98, 0x06, 0x04, 0x00); + + mipi_dsi_dcs_write_seq_multi(ctx, 0x3A, 0x70); //Data format RGB24 +}; + +static const struct drm_display_mode dmt050wvnmcmi_1a_default_mode = { + .clock = 41666, + + .hdisplay = 480, + .hsync_start = 480 + 100, + .hsync_end = 480 + 100 + 10, + .htotal = 480 + 100 + 10 + 50, + + .vdisplay = 854, + .vsync_start = 854 + 20, + .vsync_end = 854 + 20 + 4, + .vtotal = 854 + 20 + 4 + 20, + + .width_mm = 61, + .height_mm = 109, + + .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, + .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, +}; + +static const struct panel_desc dmt050wvnmcmi_1a_desc = { + .init_sequence = dmt050wvnmcmi_1a_init, + .display_mode = &dmt050wvnmcmi_1a_default_mode, + .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | + MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS, + .format = MIPI_DSI_FMT_RGB888, + .lanes = 2, +}; + static const struct of_device_id ili9806e_of_match[] = { { .compatible = "densitron,dmt028vghmcmi-1d", .data = &dmt028vghmcmi_1d_desc }, + { .compatible = "densitron,dmt050wvnmcmi-1a", .data = &dmt050wvnmcmi_1a_desc }, { .compatible = "ortustech,com35h3p70ulc", .data = &com35h3p70ulc_desc }, { } }; @@ -561,5 +760,6 @@ module_mipi_dsi_driver(ili9806e_dsi_driver); MODULE_AUTHOR("Gunnar Dibbern <[email protected]>"); MODULE_AUTHOR("Michael Walle <[email protected]>"); +MODULE_AUTHOR("Bart Steinmayr <[email protected]>"); MODULE_DESCRIPTION("Ilitek ILI9806E Controller Driver"); MODULE_LICENSE("GPL"); -- 2.47.3
