1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Samsung LTL106HL02-001 DSI panel driver
4 *
5 * Copyright (c) 2020 Anton Bambura <jenneron@protonmail.com>
6 * Copyright (c) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
7 * Copyright (c) 2024 Jonas Schw��bel <jonasschwoebel@yahoo.de>
8 */
9
10#include <backlight.h>
11#include <dm.h>
12#include <panel.h>
13#include <log.h>
14#include <mipi_dsi.h>
15#include <asm/gpio.h>
16#include <linux/delay.h>
17#include <power/regulator.h>
18
19struct samsung_ltl106hl02_priv {
20	struct udevice *vdd;
21	struct udevice *backlight;
22
23	struct gpio_desc reset_gpio;
24};
25
26static struct display_timing default_timing = {
27	.pixelclock.typ		= 137000000,
28	.hactive.typ		= 1920,
29	.hfront_porch.typ	= 32,
30	.hback_porch.typ	= 64,
31	.hsync_len.typ		= 32,
32	.vactive.typ		= 1080,
33	.vfront_porch.typ	= 2,
34	.vback_porch.typ	= 26,
35	.vsync_len.typ		= 3,
36};
37
38static int samsung_ltl106hl02_enable_backlight(struct udevice *dev)
39{
40	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
41	struct mipi_dsi_device *dsi = plat->device;
42	int ret;
43
44	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
45	if (ret < 0) {
46		log_debug("%s: failed to exit sleep mode: %d\n",
47			  __func__, ret);
48		return ret;
49	}
50	mdelay(70);
51
52	ret = mipi_dsi_dcs_set_display_on(dsi);
53	if (ret < 0) {
54		log_debug("%s: failed to enable display: %d\n",
55			  __func__, ret);
56		return ret;
57	}
58	mdelay(5);
59
60	return 0;
61}
62
63static int samsung_ltl106hl02_set_backlight(struct udevice *dev, int percent)
64{
65	struct samsung_ltl106hl02_priv *priv = dev_get_priv(dev);
66	int ret;
67
68	ret = backlight_enable(priv->backlight);
69	if (ret)
70		return ret;
71
72	return backlight_set_brightness(priv->backlight, percent);
73}
74
75static int samsung_ltl106hl02_timings(struct udevice *dev,
76				      struct display_timing *timing)
77{
78	memcpy(timing, &default_timing, sizeof(*timing));
79	return 0;
80}
81
82static int samsung_ltl106hl02_of_to_plat(struct udevice *dev)
83{
84	struct samsung_ltl106hl02_priv *priv = dev_get_priv(dev);
85	int ret;
86
87	ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
88					   "backlight", &priv->backlight);
89	if (ret) {
90		log_debug("%s: cannot get backlight: ret = %d\n",
91			  __func__, ret);
92		return ret;
93	}
94
95	ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
96					   "vdd-supply", &priv->vdd);
97	if (ret)
98		log_debug("%s: cannot get vdd-supply: error %d\n",
99			  __func__, ret);
100
101	ret = gpio_request_by_name(dev, "reset-gpios", 0,
102				   &priv->reset_gpio, GPIOD_IS_OUT);
103	if (ret)
104		log_debug("%s: cannot get reset-gpios: error %d\n",
105			  __func__, ret);
106
107	return 0;
108}
109
110static int samsung_ltl106hl02_hw_init(struct udevice *dev)
111{
112	struct samsung_ltl106hl02_priv *priv = dev_get_priv(dev);
113
114	dm_gpio_set_value(&priv->reset_gpio, 1);
115	regulator_set_enable_if_allowed(priv->vdd, 1);
116
117	/* Dataheets states at least 8.5 msec for vdd stabilization */
118	mdelay(10);
119
120	dm_gpio_set_value(&priv->reset_gpio, 0);
121
122	return 0;
123}
124
125static int samsung_ltl106hl02_probe(struct udevice *dev)
126{
127	struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
128
129	/* fill characteristics of DSI data link */
130	plat->lanes = 4;
131	plat->format = MIPI_DSI_FMT_RGB888;
132	plat->mode_flags = MIPI_DSI_MODE_VIDEO;
133
134	return samsung_ltl106hl02_hw_init(dev);
135}
136
137static const struct panel_ops samsung_ltl106hl02_ops = {
138	.enable_backlight	= samsung_ltl106hl02_enable_backlight,
139	.set_backlight		= samsung_ltl106hl02_set_backlight,
140	.get_display_timing	= samsung_ltl106hl02_timings,
141};
142
143static const struct udevice_id samsung_ltl106hl02_ids[] = {
144	{ .compatible = "samsung,ltl106hl02-001" },
145	{ }
146};
147
148U_BOOT_DRIVER(samsung_ltl106hl02) = {
149	.name		= "samsung_ltl106hl02",
150	.id		= UCLASS_PANEL,
151	.of_match	= samsung_ltl106hl02_ids,
152	.ops		= &samsung_ltl106hl02_ops,
153	.of_to_plat	= samsung_ltl106hl02_of_to_plat,
154	.probe		= samsung_ltl106hl02_probe,
155	.plat_auto	= sizeof(struct mipi_dsi_panel_plat),
156	.priv_auto	= sizeof(struct samsung_ltl106hl02_priv),
157};
158