xref: /linux/drivers/gpu/drm/panel/panel-samsung-ltl106hl02.c (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
1*ac488854SAnton Bambura // SPDX-License-Identifier: GPL-2.0-only
2*ac488854SAnton Bambura 
3*ac488854SAnton Bambura #include <linux/array_size.h>
4*ac488854SAnton Bambura #include <linux/delay.h>
5*ac488854SAnton Bambura #include <linux/err.h>
6*ac488854SAnton Bambura #include <linux/gpio/consumer.h>
7*ac488854SAnton Bambura #include <linux/mod_devicetable.h>
8*ac488854SAnton Bambura #include <linux/module.h>
9*ac488854SAnton Bambura #include <linux/property.h>
10*ac488854SAnton Bambura #include <linux/regulator/consumer.h>
11*ac488854SAnton Bambura 
12*ac488854SAnton Bambura #include <video/mipi_display.h>
13*ac488854SAnton Bambura 
14*ac488854SAnton Bambura #include <drm/drm_mipi_dsi.h>
15*ac488854SAnton Bambura #include <drm/drm_modes.h>
16*ac488854SAnton Bambura #include <drm/drm_panel.h>
17*ac488854SAnton Bambura #include <drm/drm_probe_helper.h>
18*ac488854SAnton Bambura 
19*ac488854SAnton Bambura struct samsung_ltl106hl02 {
20*ac488854SAnton Bambura 	struct drm_panel panel;
21*ac488854SAnton Bambura 	struct mipi_dsi_device *dsi;
22*ac488854SAnton Bambura 
23*ac488854SAnton Bambura 	struct regulator *supply;
24*ac488854SAnton Bambura 	struct gpio_desc *reset_gpio;
25*ac488854SAnton Bambura };
26*ac488854SAnton Bambura 
27*ac488854SAnton Bambura static inline struct samsung_ltl106hl02 *to_samsung_ltl106hl02(struct drm_panel *panel)
28*ac488854SAnton Bambura {
29*ac488854SAnton Bambura 	return container_of(panel, struct samsung_ltl106hl02, panel);
30*ac488854SAnton Bambura }
31*ac488854SAnton Bambura 
32*ac488854SAnton Bambura static void samsung_ltl106hl02_reset(struct samsung_ltl106hl02 *ctx)
33*ac488854SAnton Bambura {
34*ac488854SAnton Bambura 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
35*ac488854SAnton Bambura 	usleep_range(10000, 11000);
36*ac488854SAnton Bambura 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
37*ac488854SAnton Bambura 	usleep_range(2000, 3000);
38*ac488854SAnton Bambura }
39*ac488854SAnton Bambura 
40*ac488854SAnton Bambura static int samsung_ltl106hl02_prepare(struct drm_panel *panel)
41*ac488854SAnton Bambura {
42*ac488854SAnton Bambura 	struct samsung_ltl106hl02 *ctx = to_samsung_ltl106hl02(panel);
43*ac488854SAnton Bambura 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
44*ac488854SAnton Bambura 	struct device *dev = &ctx->dsi->dev;
45*ac488854SAnton Bambura 	int ret;
46*ac488854SAnton Bambura 
47*ac488854SAnton Bambura 	ret = regulator_enable(ctx->supply);
48*ac488854SAnton Bambura 	if (ret < 0) {
49*ac488854SAnton Bambura 		dev_err(dev, "failed to enable power supply %d\n", ret);
50*ac488854SAnton Bambura 		return ret;
51*ac488854SAnton Bambura 	}
52*ac488854SAnton Bambura 
53*ac488854SAnton Bambura 	if (ctx->reset_gpio)
54*ac488854SAnton Bambura 		samsung_ltl106hl02_reset(ctx);
55*ac488854SAnton Bambura 
56*ac488854SAnton Bambura 	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
57*ac488854SAnton Bambura 	mipi_dsi_msleep(&dsi_ctx, 70);
58*ac488854SAnton Bambura 
59*ac488854SAnton Bambura 	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
60*ac488854SAnton Bambura 	mipi_dsi_msleep(&dsi_ctx, 5);
61*ac488854SAnton Bambura 
62*ac488854SAnton Bambura 	return dsi_ctx.accum_err;
63*ac488854SAnton Bambura }
64*ac488854SAnton Bambura 
65*ac488854SAnton Bambura static int samsung_ltl106hl02_unprepare(struct drm_panel *panel)
66*ac488854SAnton Bambura {
67*ac488854SAnton Bambura 	struct samsung_ltl106hl02 *ctx = to_samsung_ltl106hl02(panel);
68*ac488854SAnton Bambura 	struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi };
69*ac488854SAnton Bambura 
70*ac488854SAnton Bambura 	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
71*ac488854SAnton Bambura 	mipi_dsi_msleep(&dsi_ctx, 50);
72*ac488854SAnton Bambura 	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
73*ac488854SAnton Bambura 	mipi_dsi_msleep(&dsi_ctx, 150);
74*ac488854SAnton Bambura 
75*ac488854SAnton Bambura 	if (ctx->reset_gpio)
76*ac488854SAnton Bambura 		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
77*ac488854SAnton Bambura 
78*ac488854SAnton Bambura 	regulator_disable(ctx->supply);
79*ac488854SAnton Bambura 
80*ac488854SAnton Bambura 	return 0;
81*ac488854SAnton Bambura }
82*ac488854SAnton Bambura 
83*ac488854SAnton Bambura static const struct drm_display_mode samsung_ltl106hl02_mode = {
84*ac488854SAnton Bambura 	.clock = (1920 + 32 + 32 + 64) * (1080 + 6 + 3 + 22) * 60 / 1000,
85*ac488854SAnton Bambura 	.hdisplay = 1920,
86*ac488854SAnton Bambura 	.hsync_start = 1920 + 32,
87*ac488854SAnton Bambura 	.hsync_end = 1920 + 32 + 32,
88*ac488854SAnton Bambura 	.htotal = 1920 + 32 + 32 + 64,
89*ac488854SAnton Bambura 	.vdisplay = 1080,
90*ac488854SAnton Bambura 	.vsync_start = 1080 + 6,
91*ac488854SAnton Bambura 	.vsync_end = 1080 + 6 + 3,
92*ac488854SAnton Bambura 	.vtotal = 1080 + 6 + 3 + 22,
93*ac488854SAnton Bambura 	.width_mm = 235,
94*ac488854SAnton Bambura 	.height_mm = 132,
95*ac488854SAnton Bambura 	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
96*ac488854SAnton Bambura };
97*ac488854SAnton Bambura 
98*ac488854SAnton Bambura static int samsung_ltl106hl02_get_modes(struct drm_panel *panel,
99*ac488854SAnton Bambura 					struct drm_connector *connector)
100*ac488854SAnton Bambura {
101*ac488854SAnton Bambura 	return drm_connector_helper_get_modes_fixed(connector, &samsung_ltl106hl02_mode);
102*ac488854SAnton Bambura }
103*ac488854SAnton Bambura 
104*ac488854SAnton Bambura static const struct drm_panel_funcs samsung_ltl106hl02_panel_funcs = {
105*ac488854SAnton Bambura 	.prepare = samsung_ltl106hl02_prepare,
106*ac488854SAnton Bambura 	.unprepare = samsung_ltl106hl02_unprepare,
107*ac488854SAnton Bambura 	.get_modes = samsung_ltl106hl02_get_modes,
108*ac488854SAnton Bambura };
109*ac488854SAnton Bambura 
110*ac488854SAnton Bambura static int samsung_ltl106hl02_probe(struct mipi_dsi_device *dsi)
111*ac488854SAnton Bambura {
112*ac488854SAnton Bambura 	struct device *dev = &dsi->dev;
113*ac488854SAnton Bambura 	struct samsung_ltl106hl02 *ctx;
114*ac488854SAnton Bambura 	int ret;
115*ac488854SAnton Bambura 
116*ac488854SAnton Bambura 	ctx = devm_drm_panel_alloc(dev, struct samsung_ltl106hl02, panel,
117*ac488854SAnton Bambura 				   &samsung_ltl106hl02_panel_funcs,
118*ac488854SAnton Bambura 				   DRM_MODE_CONNECTOR_DSI);
119*ac488854SAnton Bambura 	if (IS_ERR(ctx))
120*ac488854SAnton Bambura 		return PTR_ERR(ctx);
121*ac488854SAnton Bambura 
122*ac488854SAnton Bambura 	ctx->supply = devm_regulator_get(dev, "power");
123*ac488854SAnton Bambura 	if (IS_ERR(ctx->supply))
124*ac488854SAnton Bambura 		return dev_err_probe(dev, PTR_ERR(ctx->supply),
125*ac488854SAnton Bambura 				     "Failed to get power regulator\n");
126*ac488854SAnton Bambura 
127*ac488854SAnton Bambura 	ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
128*ac488854SAnton Bambura 	if (IS_ERR(ctx->reset_gpio))
129*ac488854SAnton Bambura 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
130*ac488854SAnton Bambura 				     "Failed to get reset-gpios\n");
131*ac488854SAnton Bambura 
132*ac488854SAnton Bambura 	ctx->dsi = dsi;
133*ac488854SAnton Bambura 	mipi_dsi_set_drvdata(dsi, ctx);
134*ac488854SAnton Bambura 
135*ac488854SAnton Bambura 	dsi->lanes = 4;
136*ac488854SAnton Bambura 	dsi->format = MIPI_DSI_FMT_RGB888;
137*ac488854SAnton Bambura 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM;
138*ac488854SAnton Bambura 
139*ac488854SAnton Bambura 	ret = drm_panel_of_backlight(&ctx->panel);
140*ac488854SAnton Bambura 	if (ret)
141*ac488854SAnton Bambura 		return dev_err_probe(dev, ret, "Failed to get backlight\n");
142*ac488854SAnton Bambura 
143*ac488854SAnton Bambura 	drm_panel_add(&ctx->panel);
144*ac488854SAnton Bambura 
145*ac488854SAnton Bambura 	ret = devm_mipi_dsi_attach(dev, dsi);
146*ac488854SAnton Bambura 	if (ret < 0) {
147*ac488854SAnton Bambura 		drm_panel_remove(&ctx->panel);
148*ac488854SAnton Bambura 		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
149*ac488854SAnton Bambura 	}
150*ac488854SAnton Bambura 
151*ac488854SAnton Bambura 	return 0;
152*ac488854SAnton Bambura }
153*ac488854SAnton Bambura 
154*ac488854SAnton Bambura static void samsung_ltl106hl02_remove(struct mipi_dsi_device *dsi)
155*ac488854SAnton Bambura {
156*ac488854SAnton Bambura 	struct samsung_ltl106hl02 *ctx = mipi_dsi_get_drvdata(dsi);
157*ac488854SAnton Bambura 
158*ac488854SAnton Bambura 	drm_panel_remove(&ctx->panel);
159*ac488854SAnton Bambura }
160*ac488854SAnton Bambura 
161*ac488854SAnton Bambura static const struct of_device_id samsung_ltl106hl02_of_match[] = {
162*ac488854SAnton Bambura 	{ .compatible = "samsung,ltl106hl02-001" },
163*ac488854SAnton Bambura 	{ /* sentinel */ }
164*ac488854SAnton Bambura };
165*ac488854SAnton Bambura MODULE_DEVICE_TABLE(of, samsung_ltl106hl02_of_match);
166*ac488854SAnton Bambura 
167*ac488854SAnton Bambura static struct mipi_dsi_driver samsung_ltl106hl02_driver = {
168*ac488854SAnton Bambura 	.driver = {
169*ac488854SAnton Bambura 		.name = "panel-samsung-ltl106hl02",
170*ac488854SAnton Bambura 		.of_match_table = samsung_ltl106hl02_of_match,
171*ac488854SAnton Bambura 	},
172*ac488854SAnton Bambura 	.probe = samsung_ltl106hl02_probe,
173*ac488854SAnton Bambura 	.remove = samsung_ltl106hl02_remove,
174*ac488854SAnton Bambura };
175*ac488854SAnton Bambura module_mipi_dsi_driver(samsung_ltl106hl02_driver);
176*ac488854SAnton Bambura 
177*ac488854SAnton Bambura MODULE_AUTHOR("Anton Bambura <jenneron@protonmail.com>");
178*ac488854SAnton Bambura MODULE_DESCRIPTION("DRM driver for Samsung LTL106HL02 video mode DSI panel");
179*ac488854SAnton Bambura MODULE_LICENSE("GPL");
180