1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Maxim MAX96752F GMSL2 Deserializer
4 *
5 * (C) Copyright 2022 Rockchip Electronics Co., Ltd
6 */
7
8 #include <config.h>
9 #include <common.h>
10 #include <backlight.h>
11 #include <errno.h>
12 #include <malloc.h>
13 #include <video.h>
14
15 #include <asm/gpio.h>
16 #include <dm/device.h>
17 #include <dm/read.h>
18 #include <dm/pinctrl.h>
19 #include <dm/uclass-id.h>
20 #include <linux/media-bus-format.h>
21
22 #include "rockchip_display.h"
23 #include "rockchip_panel.h"
24
25 struct max96752f;
26
27 struct panel_desc {
28 const char *name;
29 int (*prepare)(struct max96752f *max96752f);
30 int (*unprepare)(struct max96752f *max96752f);
31 int (*enable)(struct max96752f *max96752f);
32 int (*disable)(struct max96752f *max96752f);
33 int (*backlight_enable)(struct max96752f *max96752f);
34 int (*backlight_disable)(struct max96752f *max96752f);
35 };
36
37 struct max96752f {
38 struct udevice *dev;
39 struct udevice *serializer;
40 struct udevice *backlight;
41
42 const struct panel_desc *desc;
43 };
44
max96752f_panel_prepare(struct rockchip_panel * panel)45 static void max96752f_panel_prepare(struct rockchip_panel *panel)
46 {
47 struct max96752f *max96752f = dev_get_priv(panel->dev);
48 const struct panel_desc *desc = max96752f->desc;
49
50 if (desc->prepare)
51 desc->prepare(max96752f);
52 }
53
max96752f_panel_unprepare(struct rockchip_panel * panel)54 static void max96752f_panel_unprepare(struct rockchip_panel *panel)
55 {
56 struct max96752f *max96752f = dev_get_priv(panel->dev);
57 const struct panel_desc *desc = max96752f->desc;
58
59 if (desc->unprepare)
60 desc->unprepare(max96752f);
61 }
62
max96752f_panel_enable(struct rockchip_panel * panel)63 static void max96752f_panel_enable(struct rockchip_panel *panel)
64 {
65 struct max96752f *max96752f = dev_get_priv(panel->dev);
66 const struct panel_desc *desc = max96752f->desc;
67
68 if (desc->enable)
69 desc->enable(max96752f);
70
71 if (max96752f->backlight)
72 backlight_enable(max96752f->backlight);
73
74 if (desc->backlight_enable)
75 desc->backlight_enable(max96752f);
76 }
77
max96752f_panel_disable(struct rockchip_panel * panel)78 static void max96752f_panel_disable(struct rockchip_panel *panel)
79 {
80 struct max96752f *max96752f = dev_get_priv(panel->dev);
81 const struct panel_desc *desc = max96752f->desc;
82
83 if (desc->backlight_disable)
84 desc->backlight_disable(max96752f);
85
86 if (max96752f->backlight)
87 backlight_disable(max96752f->backlight);
88
89 if (desc->disable)
90 desc->disable(max96752f);
91 }
92
93 static const struct rockchip_panel_funcs max96752f_panel_funcs = {
94 .prepare = max96752f_panel_prepare,
95 .unprepare = max96752f_panel_unprepare,
96 .enable = max96752f_panel_enable,
97 .disable = max96752f_panel_disable,
98 };
99
max96752f_probe(struct udevice * dev)100 static int max96752f_probe(struct udevice *dev)
101 {
102 struct max96752f *max96752f = dev_get_priv(dev);
103 struct rockchip_panel *panel;
104 int ret;
105
106 ret = i2c_set_chip_offset_len(dev, 2);
107 if (ret)
108 return ret;
109
110 max96752f->dev = dev;
111 max96752f->serializer = dev->parent->parent;
112 max96752f->desc = (const struct panel_desc *)dev_get_driver_data(dev);
113
114 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
115 "backlight", &max96752f->backlight);
116 if (ret && ret != -ENOENT) {
117 dev_err(dev, "%s: Cannot get backlight: %d\n", __func__, ret);
118 return ret;
119 }
120
121 panel = calloc(1, sizeof(*panel));
122 if (!panel)
123 return -ENOMEM;
124
125 dev->driver_data = (ulong)panel;
126 panel->dev = dev;
127 panel->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
128 panel->funcs = &max96752f_panel_funcs;
129
130 return 0;
131 }
132
133 #define maxim_serializer_write(max96752f, reg, val) do { \
134 int ret; \
135 ret = dm_i2c_reg_write(max96752f->serializer, \
136 reg, val); \
137 if (ret) \
138 return ret; \
139 } while (0)
140
141 #define maxim_deserializer_write(max96752f, reg, val) do { \
142 int ret; \
143 ret = dm_i2c_reg_write(max96752f->dev, \
144 reg, val); \
145 if (ret) \
146 return ret; \
147 } while (0)
148
boe_av156fht_l83_panel_prepare(struct max96752f * max96752f)149 static int boe_av156fht_l83_panel_prepare(struct max96752f *max96752f)
150 {
151 maxim_deserializer_write(max96752f, 0x0002, 0x43);
152 maxim_deserializer_write(max96752f, 0x0140, 0x20);
153
154 maxim_deserializer_write(max96752f, 0x01ce, 0x5e); /* oldi */
155 maxim_deserializer_write(max96752f, 0x020c, 0x84); /* bl_pwm */
156 maxim_deserializer_write(max96752f, 0x0206, 0x83); /* tp_int */
157
158 maxim_deserializer_write(max96752f, 0x0215, 0x90); /* lcd_en */
159 mdelay(20);
160
161 return 0;
162 }
163
boe_av156fht_l83_panel_unprepare(struct max96752f * max96752f)164 static int boe_av156fht_l83_panel_unprepare(struct max96752f *max96752f)
165 {
166 maxim_deserializer_write(max96752f, 0x0215, 0x80); /* lcd_en */
167
168 return 0;
169 }
170
boe_av156fht_l83_panel_enable(struct max96752f * max96752f)171 static int boe_av156fht_l83_panel_enable(struct max96752f *max96752f)
172 {
173 maxim_deserializer_write(max96752f, 0x0227, 0x90); /* lcd_rst */
174 mdelay(20);
175 maxim_deserializer_write(max96752f, 0x020f, 0x90); /* tp_rst */
176 mdelay(100);
177 maxim_deserializer_write(max96752f, 0x0221, 0x90); /* lcd_stb */
178 mdelay(60);
179 maxim_deserializer_write(max96752f, 0x0212, 0x90); /* bl_current_ctl */
180 maxim_deserializer_write(max96752f, 0x0209, 0x90); /* bl_en */
181
182 return 0;
183 }
184
boe_av156fht_l83_panel_disable(struct max96752f * max96752f)185 static int boe_av156fht_l83_panel_disable(struct max96752f *max96752f)
186 {
187 maxim_deserializer_write(max96752f, 0x0209, 0x80); /* bl_en */
188 maxim_deserializer_write(max96752f, 0x0212, 0x80); /* bl_current_ctl */
189 maxim_deserializer_write(max96752f, 0x0221, 0x80); /* lcd_stb */
190 maxim_deserializer_write(max96752f, 0x020f, 0x80); /* tp_rst */
191 maxim_deserializer_write(max96752f, 0x0227, 0x80); /* lcd_rst */
192
193 return 0;
194 }
195
boe_av156fht_l83_panel_backlight_enable(struct max96752f * max96752f)196 static int boe_av156fht_l83_panel_backlight_enable(struct max96752f *max96752f)
197 {
198 maxim_deserializer_write(max96752f, 0x0212, 0x90); /* bl_current_ctl */
199 maxim_deserializer_write(max96752f, 0x0209, 0x90); /* bl_en */
200
201 return 0;
202 }
203
boe_av156fht_l83_panel_backlight_disable(struct max96752f * max96752f)204 static int boe_av156fht_l83_panel_backlight_disable(struct max96752f *max96752f)
205 {
206 maxim_deserializer_write(max96752f, 0x0209, 0x80); /* bl_en */
207 maxim_deserializer_write(max96752f, 0x0212, 0x80); /* bl_current_ctl */
208
209 return 0;
210 }
211
212 static const struct panel_desc boe_av156fht_l83 = {
213 .name = "boe-av156fht-l83",
214 .prepare = boe_av156fht_l83_panel_prepare,
215 .unprepare = boe_av156fht_l83_panel_unprepare,
216 .enable = boe_av156fht_l83_panel_enable,
217 .disable = boe_av156fht_l83_panel_disable,
218 .backlight_enable = boe_av156fht_l83_panel_backlight_enable,
219 .backlight_disable = boe_av156fht_l83_panel_backlight_disable,
220 };
221
hannstar_hsd123jpw3_a15_prepare(struct max96752f * max96752f)222 static int hannstar_hsd123jpw3_a15_prepare(struct max96752f *max96752f)
223 {
224 maxim_deserializer_write(max96752f, 0x0002, 0x43);
225 maxim_deserializer_write(max96752f, 0x0140, 0x20);
226 maxim_deserializer_write(max96752f, 0x01ce, 0x5e);
227
228 maxim_deserializer_write(max96752f, 0x0203, 0x83); /* GPIO1 <- TP_INT */
229 maxim_deserializer_write(max96752f, 0x0206, 0x84); /* GPIO2 -> TP_RST */
230 maxim_deserializer_write(max96752f, 0x0224, 0x84); /* GPIO12 -> LCD_BL_PWM */
231
232 return 0;
233 }
234
hannstar_hsd123jpw3_a15_unprepare(struct max96752f * max96752f)235 static int hannstar_hsd123jpw3_a15_unprepare(struct max96752f *max96752f)
236 {
237 return 0;
238 }
239
hannstar_hsd123jpw3_a15_enable(struct max96752f * max96752f)240 static int hannstar_hsd123jpw3_a15_enable(struct max96752f *max96752f)
241 {
242 maxim_deserializer_write(max96752f, 0x0221, 0x10); /* GPIO11 -> LCD_RESET */
243 mdelay(20);
244
245 return 0;
246 }
247
hannstar_hsd123jpw3_a15_disable(struct max96752f * max96752f)248 static int hannstar_hsd123jpw3_a15_disable(struct max96752f *max96752f)
249 {
250 maxim_deserializer_write(max96752f, 0x0221, 0x00); /* GPIO11 -> LCD_RESET */
251 mdelay(20);
252
253 return 0;
254 }
255
256 static const struct panel_desc hannstar_hsd123jpw3_a15 = {
257 .name = "hannstar,hsd123jpw3-a15",
258 .prepare = hannstar_hsd123jpw3_a15_prepare,
259 .unprepare = hannstar_hsd123jpw3_a15_unprepare,
260 .enable = hannstar_hsd123jpw3_a15_enable,
261 .disable = hannstar_hsd123jpw3_a15_disable,
262 };
263
ogm_101fhbllm01_prepare(struct max96752f * max96752f)264 static int ogm_101fhbllm01_prepare(struct max96752f *max96752f)
265 {
266 maxim_deserializer_write(max96752f, 0x01ce, 0x5e);
267
268 maxim_deserializer_write(max96752f, 0x0203, 0x84); /* GPIO1 -> BL_PWM */
269 maxim_deserializer_write(max96752f, 0x0206, 0x84); /* GPIO2 -> TP_RST */
270 maxim_deserializer_write(max96752f, 0x0209, 0x83); /* GPIO3 <- TP_INT */
271
272 maxim_deserializer_write(max96752f, 0x0001, 0x02);
273
274 return 0;
275 }
276
ogm_101fhbllm01_unprepare(struct max96752f * max96752f)277 static int ogm_101fhbllm01_unprepare(struct max96752f *max96752f)
278 {
279 maxim_deserializer_write(max96752f, 0x0001, 0x01);
280
281 return 0;
282 }
283
284 static const struct panel_desc ogm_101fhbllm01 = {
285 .name = "ogm,101fhbllm01",
286 .prepare = ogm_101fhbllm01_prepare,
287 .unprepare = ogm_101fhbllm01_unprepare,
288 };
289
290 static const struct udevice_id max96752f_of_match[] = {
291 { .compatible = "boe,av156fht-l83", .data = (ulong)&boe_av156fht_l83 },
292 { .compatible = "hannstar,hsd123jpw3-a15", .data = (ulong)&hannstar_hsd123jpw3_a15 },
293 { .compatible = "ogm,101fhbllm01", .data = (ulong)&ogm_101fhbllm01 },
294 {}
295 };
296
297 U_BOOT_DRIVER(max96752f) = {
298 .name = "max96752f",
299 .id = UCLASS_PANEL,
300 .of_match = max96752f_of_match,
301 .probe = max96752f_probe,
302 .priv_auto_alloc_size = sizeof(struct max96752f),
303 };
304