blob: 610a06ffe7b12e4ace96614499db92b644b82e28 [file] [log] [blame]
Svyatoslav Ryhel9497e752024-01-31 08:57:15 +02001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * LG LD070WX3-SL01 DSI panel driver
4 *
5 * Copyright (c) 2023 Svyatoslav Ryhel <clamor95@gmail.com>
6 */
7
8#include <backlight.h>
9#include <dm.h>
10#include <panel.h>
11#include <log.h>
12#include <mipi_dsi.h>
13#include <linux/delay.h>
14#include <power/regulator.h>
15
16struct lg_ld070wx3_priv {
17 struct udevice *vdd;
18 struct udevice *vcc;
19
20 struct udevice *backlight;
21};
22
23static struct display_timing default_timing = {
24 .pixelclock.typ = 70000000,
25 .hactive.typ = 800,
26 .hfront_porch.typ = 32,
27 .hback_porch.typ = 48,
28 .hsync_len.typ = 8,
29 .vactive.typ = 1280,
30 .vfront_porch.typ = 5,
31 .vback_porch.typ = 3,
32 .vsync_len.typ = 1,
33};
34
35static void dcs_write_one(struct mipi_dsi_device *dsi, u8 cmd, u8 data)
36{
37 mipi_dsi_dcs_write(dsi, cmd, &data, 1);
38}
39
40static int lg_ld070wx3_enable_backlight(struct udevice *dev)
41{
42 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
43 struct mipi_dsi_device *dsi = plat->device;
44 int ret;
45
46 ret = mipi_dsi_dcs_soft_reset(dsi);
47 if (ret < 0) {
48 log_debug("%s: failed to soft reset panel: %d\n",
49 __func__, ret);
50 return ret;
51 }
52
53 /* Delay before sending new command after soft reset */
54 mdelay(20);
55
56 /* Differential input impedance selection */
57 dcs_write_one(dsi, 0xAE, 0x0B);
58
59 /* Enter test mode 1 and 2*/
60 dcs_write_one(dsi, 0xEE, 0xEA);
61 dcs_write_one(dsi, 0xEF, 0x5F);
62
63 /* Increased MIPI CLK driving ability */
64 dcs_write_one(dsi, 0xF2, 0x68);
65
66 /* Exit test mode 1 and 2 */
67 dcs_write_one(dsi, 0xEE, 0x00);
68 dcs_write_one(dsi, 0xEF, 0x00);
69
70 return 0;
71}
72
73static int lg_ld070wx3_set_backlight(struct udevice *dev, int percent)
74{
75 struct lg_ld070wx3_priv *priv = dev_get_priv(dev);
76 int ret;
77
78 ret = backlight_enable(priv->backlight);
79 if (ret)
80 return ret;
81
82 return backlight_set_brightness(priv->backlight, percent);
83}
84
85static int lg_ld070wx3_timings(struct udevice *dev,
86 struct display_timing *timing)
87{
88 memcpy(timing, &default_timing, sizeof(*timing));
89 return 0;
90}
91
92static int lg_ld070wx3_of_to_plat(struct udevice *dev)
93{
94 struct lg_ld070wx3_priv *priv = dev_get_priv(dev);
95 int ret;
96
97 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
98 "backlight", &priv->backlight);
99 if (ret) {
100 log_debug("%s: cannot get backlight: ret = %d\n",
101 __func__, ret);
102 return ret;
103 }
104
105 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
106 "vdd-supply", &priv->vdd);
107 if (ret) {
108 log_debug("%s: cannot get vdd-supply: ret = %d\n",
109 __func__, ret);
110 return ret;
111 }
112
113 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
114 "vcc-supply", &priv->vcc);
115 if (ret) {
116 log_debug("%s: cannot get vcc-supply: ret = %d\n",
117 __func__, ret);
118 return ret;
119 }
120
121 return 0;
122}
123
124static int lg_ld070wx3_hw_init(struct udevice *dev)
125{
126 struct lg_ld070wx3_priv *priv = dev_get_priv(dev);
127 int ret;
128
129 ret = regulator_set_enable_if_allowed(priv->vcc, 1);
130 if (ret) {
131 log_debug("%s: enabling vcc-supply failed (%d)\n",
132 __func__, ret);
133 return ret;
134 }
135
136 ret = regulator_set_enable_if_allowed(priv->vdd, 1);
137 if (ret) {
138 log_debug("%s: enabling vdd-supply failed (%d)\n",
139 __func__, ret);
140 return ret;
141 }
142
143 /*
144 * According to spec delay between enabling supply is 0,
145 * for regulators to reach required voltage ~5ms needed.
146 * MIPI interface signal for setup requires additional
147 * 110ms which in total results in 115ms.
148 */
149 mdelay(115);
150
151 return 0;
152}
153
154static int lg_ld070wx3_probe(struct udevice *dev)
155{
156 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
157
158 /* fill characteristics of DSI data link */
159 plat->lanes = 4;
160 plat->format = MIPI_DSI_FMT_RGB888;
161 plat->mode_flags = MIPI_DSI_MODE_VIDEO;
162
163 return lg_ld070wx3_hw_init(dev);
164}
165
166static const struct panel_ops lg_ld070wx3_ops = {
167 .enable_backlight = lg_ld070wx3_enable_backlight,
168 .set_backlight = lg_ld070wx3_set_backlight,
169 .get_display_timing = lg_ld070wx3_timings,
170};
171
172static const struct udevice_id lg_ld070wx3_ids[] = {
173 { .compatible = "lg,ld070wx3-sl01" },
174 { }
175};
176
177U_BOOT_DRIVER(lg_ld070wx3) = {
178 .name = "lg_ld070wx3",
179 .id = UCLASS_PANEL,
180 .of_match = lg_ld070wx3_ids,
181 .ops = &lg_ld070wx3_ops,
182 .of_to_plat = lg_ld070wx3_of_to_plat,
183 .probe = lg_ld070wx3_probe,
184 .plat_auto = sizeof(struct mipi_dsi_panel_plat),
185 .priv_auto = sizeof(struct lg_ld070wx3_priv),
186};