blob: a3697bce5ee3a6de40edac9a7aaed3b0c68bf1a7 [file] [log] [blame]
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Renesas R61307 panel driver
4 *
5 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
6 */
7
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +03008#include <backlight.h>
9#include <dm.h>
10#include <panel.h>
11#include <log.h>
12#include <misc.h>
13#include <mipi_display.h>
14#include <mipi_dsi.h>
15#include <asm/gpio.h>
16#include <linux/delay.h>
17#include <linux/err.h>
18#include <power/regulator.h>
19
20/*
Michal Simekcc046dc2024-04-16 08:55:19 +020021 * The datasheet is not publicly available, all values are
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +030022 * taken from the downstream. If you have access to datasheets,
23 * corrections are welcome.
24 */
25
26#define R61307_MACP 0xB0 /* Manufacturer CMD Protect */
27
28#define R61307_INVERSION 0xC1
29#define R61307_GAMMA_SET_A 0xC8 /* Gamma Setting A */
30#define R61307_GAMMA_SET_B 0xC9 /* Gamma Setting B */
31#define R61307_GAMMA_SET_C 0xCA /* Gamma Setting C */
32#define R61307_CONTRAST_SET 0xCC
33
34struct renesas_r61307_priv {
35 struct udevice *vcc;
36 struct udevice *iovcc;
37
38 struct udevice *backlight;
39
40 struct gpio_desc reset_gpio;
41
42 bool dig_cont_adj;
43 bool inversion;
44 u32 gamma;
45};
46
47static const u8 macp_on[] = {
48 R61307_MACP, 0x03
49};
50
51static const u8 macp_off[] = {
52 R61307_MACP, 0x04
53};
54
55static const u8 address_mode[] = {
56 MIPI_DCS_SET_ADDRESS_MODE
57};
58
59static const u8 contrast_setting[] = {
60 R61307_CONTRAST_SET,
61 0xdc, 0xb4, 0xff
62};
63
64static const u8 column_inversion[] = {
65 R61307_INVERSION,
66 0x00, 0x50, 0x03, 0x22,
67 0x16, 0x06, 0x60, 0x11
68};
69
70static const u8 line_inversion[] = {
71 R61307_INVERSION,
72 0x00, 0x10, 0x03, 0x22,
73 0x16, 0x06, 0x60, 0x01
74};
75
76static const u8 gamma_setting[][25] = {
77 {},
78 {
79 R61307_GAMMA_SET_A,
80 0x00, 0x06, 0x0a, 0x0f,
81 0x14, 0x1f, 0x1f, 0x17,
82 0x12, 0x0c, 0x09, 0x06,
83 0x00, 0x06, 0x0a, 0x0f,
84 0x14, 0x1f, 0x1f, 0x17,
85 0x12, 0x0c, 0x09, 0x06
86 },
87 {
88 R61307_GAMMA_SET_A,
89 0x00, 0x05, 0x0b, 0x0f,
90 0x11, 0x1d, 0x20, 0x18,
91 0x18, 0x09, 0x07, 0x06,
92 0x00, 0x05, 0x0b, 0x0f,
93 0x11, 0x1d, 0x20, 0x18,
94 0x18, 0x09, 0x07, 0x06
95 },
96 {
97 R61307_GAMMA_SET_A,
98 0x0b, 0x0d, 0x10, 0x14,
99 0x13, 0x1d, 0x20, 0x18,
100 0x12, 0x09, 0x07, 0x06,
101 0x0a, 0x0c, 0x10, 0x14,
102 0x13, 0x1d, 0x20, 0x18,
103 0x12, 0x09, 0x07, 0x06
104 },
105};
106
107static struct display_timing default_timing = {
108 .pixelclock.typ = 62000000,
109 .hactive.typ = 768,
110 .hfront_porch.typ = 116,
111 .hback_porch.typ = 81,
112 .hsync_len.typ = 5,
113 .vactive.typ = 1024,
114 .vfront_porch.typ = 24,
115 .vback_porch.typ = 8,
116 .vsync_len.typ = 2,
117};
118
119static int renesas_r61307_enable_backlight(struct udevice *dev)
120{
121 struct renesas_r61307_priv *priv = dev_get_priv(dev);
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300122 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
123 struct mipi_dsi_device *dsi = plat->device;
124 int ret;
125
126 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
127 if (ret < 0) {
128 log_err("failed to exit sleep mode: %d\n", ret);
129 return ret;
130 }
131
132 mdelay(80);
133
134 mipi_dsi_dcs_write_buffer(dsi, address_mode,
135 sizeof(address_mode));
136
137 mdelay(20);
138
139 ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
140 if (ret < 0) {
141 log_err("failed to set pixel format: %d\n", ret);
142 return ret;
143 }
144
145 /* MACP Off */
146 mipi_dsi_generic_write(dsi, macp_off, sizeof(macp_off));
147
148 if (priv->dig_cont_adj)
149 mipi_dsi_generic_write(dsi, contrast_setting,
150 sizeof(contrast_setting));
151
152 if (priv->gamma)
153 mipi_dsi_generic_write(dsi, gamma_setting[priv->gamma],
154 sizeof(gamma_setting[priv->gamma]));
155
156 if (priv->inversion)
157 mipi_dsi_generic_write(dsi, column_inversion,
158 sizeof(column_inversion));
159 else
160 mipi_dsi_generic_write(dsi, line_inversion,
161 sizeof(line_inversion));
162
163 /* MACP On */
164 mipi_dsi_generic_write(dsi, macp_on, sizeof(macp_on));
165
166 ret = mipi_dsi_dcs_set_display_on(dsi);
167 if (ret < 0) {
168 log_err("failed to set display on: %d\n", ret);
169 return ret;
170 }
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300171 mdelay(50);
172
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200173 return 0;
174}
175
176static int renesas_r61307_set_backlight(struct udevice *dev, int percent)
177{
178 struct renesas_r61307_priv *priv = dev_get_priv(dev);
179 int ret;
180
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300181 ret = backlight_enable(priv->backlight);
182 if (ret)
183 return ret;
184
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200185 mdelay(5);
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300186
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200187 return backlight_set_brightness(priv->backlight, percent);
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300188}
189
190static int renesas_r61307_timings(struct udevice *dev,
191 struct display_timing *timing)
192{
193 memcpy(timing, &default_timing, sizeof(*timing));
194 return 0;
195}
196
197static int renesas_r61307_of_to_plat(struct udevice *dev)
198{
199 struct renesas_r61307_priv *priv = dev_get_priv(dev);
200 int ret;
201
202 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
203 "backlight", &priv->backlight);
204 if (ret) {
205 log_err("Cannot get backlight: ret = %d\n", ret);
206 return ret;
207 }
208
209 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
210 "vcc-supply", &priv->vcc);
211 if (ret) {
212 log_err("Cannot get vcc-supply: ret = %d\n", ret);
213 return ret;
214 }
215
216 ret = uclass_get_device_by_phandle(UCLASS_REGULATOR, dev,
217 "iovcc-supply", &priv->iovcc);
218 if (ret) {
219 log_err("Cannot get iovcc-supply: ret = %d\n", ret);
220 return ret;
221 }
222
223 ret = gpio_request_by_name(dev, "reset-gpios", 0,
224 &priv->reset_gpio, GPIOD_IS_OUT);
225 if (ret) {
226 log_err("Could not decode reser-gpios (%d)\n", ret);
227 return ret;
228 }
229
230 priv->dig_cont_adj = dev_read_bool(dev, "renesas,contrast");
231 priv->inversion = dev_read_bool(dev, "renesas,inversion");
232 priv->gamma = dev_read_u32_default(dev, "renesas,gamma", 0);
233
234 return 0;
235}
236
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200237static int renesas_r61307_hw_init(struct udevice *dev)
238{
239 struct renesas_r61307_priv *priv = dev_get_priv(dev);
240 int ret;
241
242 ret = regulator_set_enable_if_allowed(priv->vcc, 1);
243 if (ret) {
244 log_debug("%s: enabling vcc-supply failed (%d)\n",
245 __func__, ret);
246 return ret;
247 }
248 mdelay(5);
249
250 ret = regulator_set_enable_if_allowed(priv->iovcc, 1);
251 if (ret) {
252 log_debug("%s: enabling iovcc-supply failed (%d)\n",
253 __func__, ret);
254 return ret;
255 }
256
257 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
258 if (ret) {
259 log_debug("%s: changing reset-gpio failed (%d)\n",
260 __func__, ret);
261 return ret;
262 }
263 mdelay(5);
264
265 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
266 if (ret) {
267 log_debug("%s: changing reset-gpio failed (%d)\n",
268 __func__, ret);
269 return ret;
270 }
271
272 mdelay(5);
273
274 return 0;
275}
276
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300277static int renesas_r61307_probe(struct udevice *dev)
278{
279 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
280
281 /* fill characteristics of DSI data link */
282 plat->lanes = 4;
283 plat->format = MIPI_DSI_FMT_RGB888;
284 plat->mode_flags = MIPI_DSI_MODE_VIDEO;
285
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200286 return renesas_r61307_hw_init(dev);
Svyatoslav Ryhelb9054982023-04-25 10:51:44 +0300287}
288
289static const struct panel_ops renesas_r61307_ops = {
290 .enable_backlight = renesas_r61307_enable_backlight,
291 .set_backlight = renesas_r61307_set_backlight,
292 .get_display_timing = renesas_r61307_timings,
293};
294
295static const struct udevice_id renesas_r61307_ids[] = {
296 { .compatible = "koe,tx13d100vm0eaa" },
297 { .compatible = "hitachi,tx13d100vm0eaa" },
298 { }
299};
300
301U_BOOT_DRIVER(renesas_r61307) = {
302 .name = "renesas_r61307",
303 .id = UCLASS_PANEL,
304 .of_match = renesas_r61307_ids,
305 .ops = &renesas_r61307_ops,
306 .of_to_plat = renesas_r61307_of_to_plat,
307 .probe = renesas_r61307_probe,
308 .plat_auto = sizeof(struct mipi_dsi_panel_plat),
309 .priv_auto = sizeof(struct renesas_r61307_priv),
310};