1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Rohm BU18RL82-based panel driver
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 bu18rl82;
26
27 struct panel_desc {
28 const char *name;
29 int (*prepare)(struct bu18rl82 *rl82);
30 int (*unprepare)(struct bu18rl82 *rl82);
31 int (*enable)(struct bu18rl82 *rl82);
32 int (*disable)(struct bu18rl82 *rl82);
33 int (*backlight_enable)(struct bu18rl82 *rl82);
34 int (*backlight_disable)(struct bu18rl82 *rl82);
35 };
36
37 struct bu18rl82 {
38 struct udevice *dev;
39 struct udevice *backlight;
40 const struct panel_desc *desc;
41 };
42
bu18rl82_panel_prepare(struct rockchip_panel * panel)43 static void bu18rl82_panel_prepare(struct rockchip_panel *panel)
44 {
45 struct bu18rl82 *rl82 = dev_get_priv(panel->dev);
46 const struct panel_desc *desc = rl82->desc;
47
48 if (desc->prepare)
49 desc->prepare(rl82);
50 }
51
bu18rl82_panel_unprepare(struct rockchip_panel * panel)52 static void bu18rl82_panel_unprepare(struct rockchip_panel *panel)
53 {
54 struct bu18rl82 *rl82 = dev_get_priv(panel->dev);
55 const struct panel_desc *desc = rl82->desc;
56
57 if (desc->unprepare)
58 desc->unprepare(rl82);
59 }
60
bu18rl82_panel_enable(struct rockchip_panel * panel)61 static void bu18rl82_panel_enable(struct rockchip_panel *panel)
62 {
63 struct bu18rl82 *rl82 = dev_get_priv(panel->dev);
64 const struct panel_desc *desc = rl82->desc;
65
66 if (desc->enable)
67 desc->enable(rl82);
68
69 if (rl82->backlight)
70 backlight_enable(rl82->backlight);
71
72 if (desc->backlight_enable)
73 desc->backlight_enable(rl82);
74 }
75
bu18rl82_panel_disable(struct rockchip_panel * panel)76 static void bu18rl82_panel_disable(struct rockchip_panel *panel)
77 {
78 struct bu18rl82 *rl82 = dev_get_priv(panel->dev);
79 const struct panel_desc *desc = rl82->desc;
80
81 if (desc->backlight_disable)
82 desc->backlight_disable(rl82);
83
84 if (rl82->backlight)
85 backlight_disable(rl82->backlight);
86
87 if (desc->disable)
88 desc->disable(rl82);
89 }
90
91 static const struct rockchip_panel_funcs bu18rl82_panel_funcs = {
92 .prepare = bu18rl82_panel_prepare,
93 .unprepare = bu18rl82_panel_unprepare,
94 .enable = bu18rl82_panel_enable,
95 .disable = bu18rl82_panel_disable,
96 };
97
bu18rl82_probe(struct udevice * dev)98 static int bu18rl82_probe(struct udevice *dev)
99 {
100 struct bu18rl82 *rl82 = dev_get_priv(dev);
101 struct rockchip_panel *panel;
102 int ret;
103
104 ret = i2c_set_chip_offset_len(dev, 2);
105 if (ret)
106 return ret;
107
108 rl82->dev = dev;
109 rl82->desc = (const struct panel_desc *)dev_get_driver_data(dev);
110
111 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
112 "backlight", &rl82->backlight);
113 if (ret && ret != -ENOENT) {
114 dev_err(dev, "%s: Cannot get backlight: %d\n", __func__, ret);
115 return ret;
116 }
117
118 panel = calloc(1, sizeof(*panel));
119 if (!panel)
120 return -ENOMEM;
121
122 dev->driver_data = (ulong)panel;
123 panel->dev = dev;
124 panel->bus_format = MEDIA_BUS_FMT_RGB888_1X24;
125 panel->funcs = &bu18rl82_panel_funcs;
126
127 return 0;
128 }
129
130 #define rohm_deserializer_write(rl82, reg, val) do { \
131 int ret; \
132 ret = dm_i2c_reg_write(rl82->dev, reg, val); \
133 if (ret) { \
134 dev_err(rl82->dev, \
135 "failed to set register 0x%04x\n", \
136 reg); \
137 return ret; \
138 } \
139 } while (0)
140
csot_mg1561b01_prepare(struct bu18rl82 * rl82)141 static int csot_mg1561b01_prepare(struct bu18rl82 *rl82)
142 {
143 const struct reg_sequence {
144 u16 reg;
145 u8 def;
146 } regs[] = {
147 { 0x0011, 0x03 }, { 0x0012, 0x03 },
148 { 0x001f, 0x02 }, { 0x0020, 0x02 },
149 { 0x0031, 0x41 }, { 0x0032, 0x41 },
150 { 0x0073, 0x80 }, { 0x0074, 0x07 },
151 { 0x007b, 0x38 }, { 0x007c, 0x04 },
152 { 0x0079, 0x0a },
153 { 0x0429, 0x0a }, { 0x045d, 0x01 },
154 { 0x0529, 0x0a }, { 0x055d, 0x01 },
155 { 0x060a, 0xb0 }, { 0x060b, 0xff }, { 0x060c, 0xff },
156 { 0x0644, 0x18 }, { 0x0645, 0x01 }, { 0x0646, 0x2d },
157 };
158 int i;
159
160 for (i = 0; i < ARRAY_SIZE(regs); i++)
161 rohm_deserializer_write(rl82, regs[i].reg, regs[i].def);
162
163 /* BL_PWM - GPIO0 */
164 rohm_deserializer_write(rl82, 0x0057, 0x00);
165 rohm_deserializer_write(rl82, 0x0058, 0x02);
166
167 /* TP_INT - GPIO3 */
168 rohm_deserializer_write(rl82, 0x0060, 0x08);
169 rohm_deserializer_write(rl82, 0x042e, 0x05);
170
171 /* TP_RST - GPIO4 */
172 rohm_deserializer_write(rl82, 0x0063, 0x00);
173 rohm_deserializer_write(rl82, 0x0064, 0x01);
174
175 return 0;
176 }
177
csot_mg1561b01_unprepare(struct bu18rl82 * rl82)178 static int csot_mg1561b01_unprepare(struct bu18rl82 *rl82)
179 {
180 /* TP_RST - GPIO4 */
181 rohm_deserializer_write(rl82, 0x0064, 0x00);
182
183 return 0;
184 }
185
csot_mg1561b01_enable(struct bu18rl82 * rl82)186 static int csot_mg1561b01_enable(struct bu18rl82 *rl82)
187 {
188 rohm_deserializer_write(rl82, 0x0091, 0x03);
189 rohm_deserializer_write(rl82, 0x0090, 0x01);
190
191 return 0;
192 }
193
csot_mg1561b01_disable(struct bu18rl82 * rl82)194 static int csot_mg1561b01_disable(struct bu18rl82 *rl82)
195 {
196 rohm_deserializer_write(rl82, 0x0090, 0x00);
197 rohm_deserializer_write(rl82, 0x0091, 0x00);
198
199 return 0;
200 }
201
csot_mg1561b01_backlight_enable(struct bu18rl82 * rl82)202 static int csot_mg1561b01_backlight_enable(struct bu18rl82 *rl82)
203 {
204 /* BL_EN - GPIO1 */
205 rohm_deserializer_write(rl82, 0x005a, 0x00);
206 rohm_deserializer_write(rl82, 0x005b, 0x01);
207
208 return 0;
209 }
210
csot_mg1561b01_backlight_disable(struct bu18rl82 * rl82)211 static int csot_mg1561b01_backlight_disable(struct bu18rl82 *rl82)
212 {
213 /* BL_EN - GPIO1 */
214 rohm_deserializer_write(rl82, 0x005b, 0x00);
215
216 return 0;
217 }
218
219 static const struct panel_desc csot_mg1561b01 = {
220 .name = "csot,mg1561b01",
221 .prepare = csot_mg1561b01_prepare,
222 .unprepare = csot_mg1561b01_unprepare,
223 .enable = csot_mg1561b01_enable,
224 .disable = csot_mg1561b01_disable,
225 .backlight_enable = csot_mg1561b01_backlight_enable,
226 .backlight_disable = csot_mg1561b01_backlight_disable,
227 };
228
touch_china_v123awf3_r1_prepare(struct bu18rl82 * rl82)229 static int touch_china_v123awf3_r1_prepare(struct bu18rl82 *rl82)
230 {
231 const struct reg_sequence {
232 u16 reg;
233 u8 def;
234 } regs[] = {
235 { 0x0011, 0x03 }, { 0x0012, 0x03 },
236 { 0x001f, 0x02 }, { 0x0020, 0x02 },
237 { 0x0031, 0x48 }, { 0x0032, 0x48 },
238 { 0x0073, 0x80 }, { 0x0074, 0x07 },
239 { 0x007b, 0xd0 }, { 0x007c, 0x02 },
240 { 0x0079, 0x0a },
241 { 0x0429, 0x0a }, { 0x045d, 0x01 },
242 { 0x0529, 0x0a }, { 0x055d, 0x01 },
243 { 0x060a, 0xb0 }, { 0x060b, 0xff }, { 0x060c, 0xff },
244 { 0x0644, 0x90 }, { 0x0646, 0xd2 },
245 };
246 int i;
247
248 for (i = 0; i < ARRAY_SIZE(regs); i++)
249 rohm_deserializer_write(rl82, regs[i].reg, regs[i].def);
250
251 /* TP_INT - GPIO4 */
252 rohm_deserializer_write(rl82, 0x0063, 0x08);
253 rohm_deserializer_write(rl82, 0x042f, 0x06);
254
255 /* TP_RST - GPIO3 */
256 rohm_deserializer_write(rl82, 0x0060, 0x00);
257 rohm_deserializer_write(rl82, 0x0061, 0x00);
258
259 /* LCD_BIAS_EN - GPIO2 */
260 rohm_deserializer_write(rl82, 0x005d, 0x00);
261 rohm_deserializer_write(rl82, 0x005e, 0x01);
262 mdelay(6);
263
264 return 0;
265 }
266
touch_china_v123awf3_r1_unprepare(struct bu18rl82 * rl82)267 static int touch_china_v123awf3_r1_unprepare(struct bu18rl82 *rl82)
268 {
269 /* LCD_BIAS_EN - GPIO2 */
270 rohm_deserializer_write(rl82, 0x005e, 0x00);
271
272 return 0;
273 }
274
touch_china_v123awf3_r1_enable(struct bu18rl82 * rl82)275 static int touch_china_v123awf3_r1_enable(struct bu18rl82 *rl82)
276 {
277 rohm_deserializer_write(rl82, 0x0091, 0x03);
278 rohm_deserializer_write(rl82, 0x0090, 0x01);
279
280 /* RSEX - GPIO5 */
281 rohm_deserializer_write(rl82, 0x0066, 0x00);
282 rohm_deserializer_write(rl82, 0x0067, 0x01);
283 /* TP_RST - GPIO3 */
284 rohm_deserializer_write(rl82, 0x0060, 0x00);
285 rohm_deserializer_write(rl82, 0x0061, 0x01);
286 mdelay(20);
287 /* LCD_PON - GPIO1 */
288 rohm_deserializer_write(rl82, 0x005a, 0x00);
289 rohm_deserializer_write(rl82, 0x005b, 0x01);
290
291 return 0;
292 }
293
touch_china_v123awf3_r1_disable(struct bu18rl82 * rl82)294 static int touch_china_v123awf3_r1_disable(struct bu18rl82 *rl82)
295 {
296 rohm_deserializer_write(rl82, 0x0090, 0x00);
297 rohm_deserializer_write(rl82, 0x0091, 0x00);
298
299 /* LCD_PON - GPIO1 */
300 rohm_deserializer_write(rl82, 0x005b, 0x00);
301 mdelay(100);
302 /* TP_RST - GPIO3 */
303 rohm_deserializer_write(rl82, 0x0061, 0x00);
304 /* RSEX - GPIO5 */
305 rohm_deserializer_write(rl82, 0x0067, 0x00);
306
307 return 0;
308 }
309
touch_china_v123awf3_r1_backlight_enable(struct bu18rl82 * rl82)310 static int touch_china_v123awf3_r1_backlight_enable(struct bu18rl82 *rl82)
311 {
312 /* BL_PWM - GPIO0 */
313 rohm_deserializer_write(rl82, 0x0057, 0x00);
314 rohm_deserializer_write(rl82, 0x0058, 0x02);
315
316 return 0;
317 }
318
touch_china_v123awf3_r1_backlight_disable(struct bu18rl82 * rl82)319 static int touch_china_v123awf3_r1_backlight_disable(struct bu18rl82 *rl82)
320 {
321 /* BL_PWM - GPIO0 */
322 rohm_deserializer_write(rl82, 0x0058, 0x00);
323
324 return 0;
325 }
326
327 static const struct panel_desc touch_china_v123awf3_r1 = {
328 .name = "touch-china,v123awf3-r1",
329 .prepare = touch_china_v123awf3_r1_prepare,
330 .unprepare = touch_china_v123awf3_r1_unprepare,
331 .enable = touch_china_v123awf3_r1_enable,
332 .disable = touch_china_v123awf3_r1_disable,
333 .backlight_enable = touch_china_v123awf3_r1_backlight_enable,
334 .backlight_disable = touch_china_v123awf3_r1_backlight_disable,
335 };
336
337 static const struct udevice_id bu18rl82_of_match[] = {
338 { .compatible = "csot,mg1561b01", .data = (ulong)&csot_mg1561b01 },
339 { .compatible = "touch-china,v123awf3-r1", .data = (ulong)&touch_china_v123awf3_r1 },
340 {}
341 };
342
343 U_BOOT_DRIVER(panel_rohm_bu18rl82) = {
344 .name = "panel-rohm-bu18rl82",
345 .id = UCLASS_PANEL,
346 .of_match = bu18rl82_of_match,
347 .probe = bu18rl82_probe,
348 .priv_auto_alloc_size = sizeof(struct bu18rl82),
349 };
350