brintos

brintos / linux-shallow public Read only

0
0
Text · 14.0 KiB · 0b87f1e Raw
440 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2023 Alexander Warnecke <awarnecke002@hotmail.com>4 * Copyright (c) 2023 Manuel Traut <manut@mecka.net>5 * Copyright (c) 2023 Dang Huynh <danct12@riseup.net>6 */7 8#include <linux/delay.h>9#include <linux/gpio/consumer.h>10#include <linux/module.h>11#include <linux/of.h>12#include <linux/of_device.h>13#include <linux/regulator/consumer.h>14 15#include <drm/drm_connector.h>16#include <drm/drm_mipi_dsi.h>17#include <drm/drm_modes.h>18#include <drm/drm_panel.h>19#include <drm/drm_probe_helper.h>20 21struct boe_th101mb31ig002;22 23struct panel_desc {24	const struct drm_display_mode *modes;25	unsigned long mode_flags;26	enum mipi_dsi_pixel_format format;27	int (*init)(struct boe_th101mb31ig002 *ctx);28	unsigned int lanes;29	bool lp11_before_reset;30	unsigned int vcioo_to_lp11_delay_ms;31	unsigned int lp11_to_reset_delay_ms;32	unsigned int backlight_off_to_display_off_delay_ms;33	unsigned int enter_sleep_to_reset_down_delay_ms;34	unsigned int power_off_delay_ms;35};36 37struct boe_th101mb31ig002 {38	struct drm_panel panel;39 40	struct mipi_dsi_device *dsi;41 42	const struct panel_desc *desc;43 44	struct regulator *power;45	struct gpio_desc *enable;46	struct gpio_desc *reset;47 48	enum drm_panel_orientation orientation;49};50 51static void boe_th101mb31ig002_reset(struct boe_th101mb31ig002 *ctx)52{53	gpiod_direction_output(ctx->reset, 0);54	usleep_range(10, 100);55	gpiod_direction_output(ctx->reset, 1);56	usleep_range(10, 100);57	gpiod_direction_output(ctx->reset, 0);58	usleep_range(5000, 6000);59}60 61static int boe_th101mb31ig002_enable(struct boe_th101mb31ig002 *ctx)62{63	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };64 65	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);66	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);67	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);68	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);69	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);70	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);71	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10,72					       0x00);73	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x48, 0x00,74					       0x00);75	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x65, 0x55, 0x49, 0x46, 0x36,76					       0x3b, 0x24, 0x3d, 0x3c, 0x3d, 0x5c, 0x4c,77					       0x55, 0x47, 0x46, 0x39, 0x26, 0x06, 0x7c,78					       0x65, 0x55, 0x49, 0x46, 0x36, 0x3b, 0x24,79					       0x3d, 0x3c, 0x3d, 0x5c, 0x4c, 0x55, 0x47,80					       0x46, 0x39, 0x26, 0x06);81	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x00, 0xff, 0x87, 0x12, 0x34, 0x44, 0x44,82					       0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0f,83					       0x00, 0x00, 0xc1);84	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00,85					       0x7f, 0x00, 0x54, 0x00);86	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11,87					       0x22, 0x20, 0x44, 0xff, 0x18, 0x00);88	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x86, 0x46, 0x05, 0x05, 0x1c, 0x1c,89					       0x1d, 0x1d, 0x02, 0x1f, 0x1f, 0x1e, 0x1e,90					       0x0f, 0x0f, 0x0d, 0x0d, 0x13, 0x13, 0x11,91					       0x11, 0x00);92	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x07, 0x07, 0x04, 0x04, 0x1c, 0x1c,93					       0x1d, 0x1d, 0x02, 0x1f, 0x1f, 0x1e, 0x1e,94					       0x0e, 0x0e, 0x0c, 0x0c, 0x12, 0x12, 0x10,95					       0x10, 0x00);96	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc6, 0x2a, 0x2a);97	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);98	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);99	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b,100					       0x06, 0xb3);101	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x00);102	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44,103					       0x08, 0x10, 0x00, 0x00, 0x00);104	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff,105					       0xff, 0xff);106	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);107	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);108 109	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);110 111	mipi_dsi_msleep(&dsi_ctx, 120);112 113	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);114 115	return dsi_ctx.accum_err;116}117 118static int starry_er88577_init_cmd(struct boe_th101mb31ig002 *ctx)119{120	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };121 122	msleep(70);123 124	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe0, 0xab, 0xba);125	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe1, 0xba, 0xab);126	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb1, 0x10, 0x01, 0x47, 0xff);127	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb2, 0x0c, 0x14, 0x04, 0x50, 0x50, 0x14);128	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb3, 0x56, 0x53, 0x00);129	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb4, 0x33, 0x30, 0x04);130	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb6, 0xb0, 0x00, 0x00, 0x10, 0x00, 0x10,131					       0x00);132	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb8, 0x05, 0x12, 0x29, 0x49, 0x40);133	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xb9, 0x7c, 0x61, 0x4f, 0x42, 0x3e, 0x2d,134					       0x31, 0x1a, 0x33, 0x33, 0x33, 0x52, 0x40,135					       0x47, 0x38, 0x34, 0x26, 0x0e, 0x06, 0x7c,136					       0x61, 0x4f, 0x42, 0x3e, 0x2d, 0x31, 0x1a,137					       0x33, 0x33, 0x33, 0x52, 0x40, 0x47, 0x38,138					       0x34, 0x26, 0x0e, 0x06);139	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xcc, 0x76, 0x12, 0x34, 0x44, 0x44,140					       0x44, 0x44, 0x98, 0x04, 0x98, 0x04, 0x0f,141					       0x00, 0x00, 0xc1);142	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0x54, 0x94, 0x02, 0x85, 0x9f, 0x00,143					       0x6f, 0x00, 0x54, 0x00);144	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x17, 0x09, 0x08, 0x89, 0x08, 0x11,145					       0x22, 0x20, 0x44, 0xff, 0x18, 0x00);146	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc3, 0x87, 0x47, 0x05, 0x05, 0x1c, 0x1c,147					       0x1d, 0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f,148					       0x0f, 0x0f, 0x0d, 0x0d, 0x13, 0x13, 0x11,149					       0x11, 0x24);150	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc4, 0x06, 0x06, 0x04, 0x04, 0x1c, 0x1c,151					       0x1d, 0x1d, 0x02, 0x1e, 0x1e, 0x1f, 0x1f,152					       0x0e, 0x0e, 0x0c, 0x0c, 0x12, 0x12, 0x10,153					       0x10, 0x24);154	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc8, 0x21, 0x00, 0x31, 0x42, 0x34, 0x16);155	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xca, 0xcb, 0x43);156	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xcd, 0x0e, 0x4b, 0x4b, 0x20, 0x19, 0x6b,157					       0x06, 0xb3);158	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd1, 0x40, 0x0d, 0xff, 0x0f);159	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd2, 0xe3, 0x2b, 0x38, 0x08);160	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd3, 0x00, 0x00, 0x00, 0x00,161					       0x00, 0x33, 0x20, 0x3a, 0xd5, 0x86, 0xf3);162	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xd4, 0x00, 0x01, 0x00, 0x0e, 0x04, 0x44,163					       0x08, 0x10, 0x00, 0x00, 0x00);164	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xe6, 0x80, 0x09, 0xff, 0xff, 0xff, 0xff,165					       0xff, 0xff);166	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf0, 0x12, 0x03, 0x20, 0x00, 0xff);167	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xf3, 0x00);168 169	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);170 171	mipi_dsi_msleep(&dsi_ctx, 120);172 173	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);174 175	mipi_dsi_msleep(&dsi_ctx, 20);176 177	return dsi_ctx.accum_err;178}179 180static int boe_th101mb31ig002_disable(struct drm_panel *panel)181{182	struct boe_th101mb31ig002 *ctx = container_of(panel,183						      struct boe_th101mb31ig002,184						      panel);185	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };186 187	if (ctx->desc->backlight_off_to_display_off_delay_ms)188		mipi_dsi_msleep(&dsi_ctx, ctx->desc->backlight_off_to_display_off_delay_ms);189 190	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);191 192	mipi_dsi_msleep(&dsi_ctx, 120);193 194	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);195 196	if (ctx->desc->enter_sleep_to_reset_down_delay_ms)197		mipi_dsi_msleep(&dsi_ctx, ctx->desc->enter_sleep_to_reset_down_delay_ms);198 199	return dsi_ctx.accum_err;200}201 202static int boe_th101mb31ig002_unprepare(struct drm_panel *panel)203{204	struct boe_th101mb31ig002 *ctx = container_of(panel,205						      struct boe_th101mb31ig002,206						      panel);207 208	gpiod_set_value_cansleep(ctx->reset, 1);209	gpiod_set_value_cansleep(ctx->enable, 0);210	regulator_disable(ctx->power);211 212	if (ctx->desc->power_off_delay_ms)213		msleep(ctx->desc->power_off_delay_ms);214 215	return 0;216}217 218static int boe_th101mb31ig002_prepare(struct drm_panel *panel)219{220	struct boe_th101mb31ig002 *ctx = container_of(panel,221						      struct boe_th101mb31ig002,222						      panel);223	struct device *dev = &ctx->dsi->dev;224	int ret;225 226	ret = regulator_enable(ctx->power);227	if (ret) {228		dev_err(dev, "Failed to enable power supply: %d\n", ret);229		return ret;230	}231 232	if (ctx->desc->vcioo_to_lp11_delay_ms)233		msleep(ctx->desc->vcioo_to_lp11_delay_ms);234 235	if (ctx->desc->lp11_before_reset) {236		ret = mipi_dsi_dcs_nop(ctx->dsi);237		if (ret)238			return ret;239	}240 241	if (ctx->desc->lp11_to_reset_delay_ms)242		msleep(ctx->desc->lp11_to_reset_delay_ms);243 244	gpiod_set_value_cansleep(ctx->enable, 1);245	msleep(50);246	boe_th101mb31ig002_reset(ctx);247 248	ret = ctx->desc->init(ctx);249	if (ret)250		return ret;251 252	return 0;253}254 255static const struct drm_display_mode boe_th101mb31ig002_default_mode = {256	.clock		= 73500,257	.hdisplay	= 800,258	.hsync_start	= 800 + 64,259	.hsync_end	= 800 + 64 + 16,260	.htotal		= 800 + 64 + 16 + 64,261	.vdisplay	= 1280,262	.vsync_start	= 1280 + 2,263	.vsync_end	= 1280 + 2 + 4,264	.vtotal		= 1280 + 2 + 4 + 12,265	.width_mm	= 135,266	.height_mm	= 216,267	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,268};269 270static const struct panel_desc boe_th101mb31ig002_desc = {271	.modes = &boe_th101mb31ig002_default_mode,272	.lanes = 4,273	.format = MIPI_DSI_FMT_RGB888,274	.mode_flags = MIPI_DSI_MODE_VIDEO_BURST |275			  MIPI_DSI_MODE_NO_EOT_PACKET |276			  MIPI_DSI_MODE_LPM,277	.init = boe_th101mb31ig002_enable,278};279 280static const struct drm_display_mode starry_er88577_default_mode = {281	.clock	= (800 + 25 + 25 + 25) * (1280 + 20 + 4 + 12) * 60 / 1000,282	.hdisplay = 800,283	.hsync_start = 800 + 25,284	.hsync_end = 800 + 25 + 25,285	.htotal = 800 + 25 + 25 + 25,286	.vdisplay = 1280,287	.vsync_start = 1280 + 20,288	.vsync_end = 1280 + 20 + 4,289	.vtotal = 1280 + 20 + 4 + 12,290	.width_mm = 135,291	.height_mm = 216,292	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,293};294 295static const struct panel_desc starry_er88577_desc = {296	.modes = &starry_er88577_default_mode,297	.lanes = 4,298	.format = MIPI_DSI_FMT_RGB888,299	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |300		      MIPI_DSI_MODE_LPM,301	.init = starry_er88577_init_cmd,302	.lp11_before_reset = true,303	.vcioo_to_lp11_delay_ms = 5,304	.lp11_to_reset_delay_ms = 50,305	.backlight_off_to_display_off_delay_ms = 100,306	.enter_sleep_to_reset_down_delay_ms = 100,307	.power_off_delay_ms = 1000,308};309 310static int boe_th101mb31ig002_get_modes(struct drm_panel *panel,311					struct drm_connector *connector)312{313	struct boe_th101mb31ig002 *ctx = container_of(panel,314						      struct boe_th101mb31ig002,315						      panel);316	const struct drm_display_mode *desc_mode = ctx->desc->modes;317 318	connector->display_info.bpc = 8;319	/*320	 * TODO: Remove once all drm drivers call321	 * drm_connector_set_orientation_from_panel()322	 */323	drm_connector_set_panel_orientation(connector, ctx->orientation);324 325	return drm_connector_helper_get_modes_fixed(connector, desc_mode);326}327 328static enum drm_panel_orientation329boe_th101mb31ig002_get_orientation(struct drm_panel *panel)330{331	struct boe_th101mb31ig002 *ctx = container_of(panel,332						      struct boe_th101mb31ig002,333						      panel);334 335	return ctx->orientation;336}337 338static const struct drm_panel_funcs boe_th101mb31ig002_funcs = {339	.prepare = boe_th101mb31ig002_prepare,340	.unprepare = boe_th101mb31ig002_unprepare,341	.disable = boe_th101mb31ig002_disable,342	.get_modes = boe_th101mb31ig002_get_modes,343	.get_orientation = boe_th101mb31ig002_get_orientation,344};345 346static int boe_th101mb31ig002_dsi_probe(struct mipi_dsi_device *dsi)347{348	struct boe_th101mb31ig002 *ctx;349	const struct panel_desc *desc;350	int ret;351 352	ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);353	if (!ctx)354		return -ENOMEM;355 356	mipi_dsi_set_drvdata(dsi, ctx);357	ctx->dsi = dsi;358 359	desc = of_device_get_match_data(&dsi->dev);360	dsi->lanes = desc->lanes;361	dsi->format = desc->format;362	dsi->mode_flags = desc->mode_flags;363	ctx->desc = desc;364 365	ctx->power = devm_regulator_get(&dsi->dev, "power");366	if (IS_ERR(ctx->power))367		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->power),368				     "Failed to get power regulator\n");369 370	ctx->enable = devm_gpiod_get(&dsi->dev, "enable", GPIOD_OUT_LOW);371	if (IS_ERR(ctx->enable))372		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->enable),373				     "Failed to get enable GPIO\n");374 375	ctx->reset = devm_gpiod_get_optional(&dsi->dev, "reset", GPIOD_OUT_HIGH);376	if (IS_ERR(ctx->reset))377		return dev_err_probe(&dsi->dev, PTR_ERR(ctx->reset),378				     "Failed to get reset GPIO\n");379 380	ret = of_drm_get_panel_orientation(dsi->dev.of_node,381					   &ctx->orientation);382	if (ret)383		return dev_err_probe(&dsi->dev, ret,384				     "Failed to get orientation\n");385 386	drm_panel_init(&ctx->panel, &dsi->dev, &boe_th101mb31ig002_funcs,387		       DRM_MODE_CONNECTOR_DSI);388 389	ret = drm_panel_of_backlight(&ctx->panel);390	if (ret)391		return ret;392 393	drm_panel_add(&ctx->panel);394 395	ret = mipi_dsi_attach(dsi);396	if (ret < 0) {397		dev_err_probe(&dsi->dev, ret,398			      "Failed to attach panel to DSI host\n");399		drm_panel_remove(&ctx->panel);400		return ret;401	}402 403	return 0;404}405 406static void boe_th101mb31ig002_dsi_remove(struct mipi_dsi_device *dsi)407{408	struct boe_th101mb31ig002 *ctx = mipi_dsi_get_drvdata(dsi);409 410	mipi_dsi_detach(dsi);411	drm_panel_remove(&ctx->panel);412}413 414static const struct of_device_id boe_th101mb31ig002_of_match[] = {415	{416		.compatible = "boe,th101mb31ig002-28a",417		.data = &boe_th101mb31ig002_desc418	},419	{420		.compatible = "starry,er88577",421		.data = &starry_er88577_desc422	},423	{ /* sentinel */ }424};425MODULE_DEVICE_TABLE(of, boe_th101mb31ig002_of_match);426 427static struct mipi_dsi_driver boe_th101mb31ig002_driver = {428	.driver = {429		.name = "boe-th101mb31ig002-28a",430		.of_match_table = boe_th101mb31ig002_of_match,431	},432	.probe = boe_th101mb31ig002_dsi_probe,433	.remove = boe_th101mb31ig002_dsi_remove,434};435module_mipi_dsi_driver(boe_th101mb31ig002_driver);436 437MODULE_AUTHOR("Alexander Warnecke <awarnecke002@hotmail.com>");438MODULE_DESCRIPTION("BOE TH101MB31IG002-28A MIPI-DSI LCD panel");439MODULE_LICENSE("GPL");440