blob: 0954b04b62ea358e8a90dce7364d98053ea17437 [file] [log] [blame]
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Renesas R69328 panel driver
4 *
5 * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
6 */
7
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +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 Ryhelfcbbd562023-04-25 10:51:45 +030022 * taken from the downstream. If you have access to datasheets,
23 * corrections are welcome.
24 */
25
26#define R69328_MACP 0xB0 /* Manufacturer Command Access Protect */
27
28#define R69328_GAMMA_SET_A 0xC8 /* Gamma Setting A */
29#define R69328_GAMMA_SET_B 0xC9 /* Gamma Setting B */
30#define R69328_GAMMA_SET_C 0xCA /* Gamma Setting C */
31
32#define R69328_POWER_SET 0xD1
33
34struct renesas_r69328_priv {
Svyatoslav Ryhelb600fa82025-03-04 21:29:01 +020035 struct udevice *vdd;
36 struct udevice *vddio;
37
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +030038 struct udevice *backlight;
39
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +030040 struct gpio_desc reset_gpio;
41};
42
43static const u8 address_mode[] = {
44 MIPI_DCS_SET_ADDRESS_MODE
45};
46
47#define dsi_generic_write_seq(dsi, cmd, seq...) do { \
48 static const u8 b[] = { cmd, seq }; \
49 int ret; \
50 ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
51 if (ret < 0) \
52 return ret; \
53 } while (0)
54
55static struct display_timing default_timing = {
56 .pixelclock.typ = 68000000,
57 .hactive.typ = 720,
58 .hfront_porch.typ = 92,
59 .hback_porch.typ = 62,
60 .hsync_len.typ = 4,
61 .vactive.typ = 1280,
62 .vfront_porch.typ = 6,
63 .vback_porch.typ = 3,
64 .vsync_len.typ = 1,
65};
66
67static int renesas_r69328_enable_backlight(struct udevice *dev)
68{
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +030069 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
70 struct mipi_dsi_device *dsi = plat->device;
71 int ret;
72
73 mipi_dsi_dcs_write_buffer(dsi, address_mode,
74 sizeof(address_mode));
75
76 ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
77 if (ret < 0) {
78 log_err("failed to set pixel format: %d\n", ret);
79 return ret;
80 }
81
82 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
83 if (ret < 0) {
84 log_err("failed to exit sleep mode: %d\n", ret);
85 return ret;
86 }
87
88 mdelay(100);
89
90 /* MACP Off */
91 dsi_generic_write_seq(dsi, R69328_MACP, 0x04);
92
93 dsi_generic_write_seq(dsi, R69328_POWER_SET, 0x14,
94 0x1d, 0x21, 0x67, 0x11, 0x9a);
95
96 dsi_generic_write_seq(dsi, R69328_GAMMA_SET_A, 0x00,
97 0x1a, 0x20, 0x28, 0x25, 0x24,
98 0x26, 0x15, 0x13, 0x11, 0x18,
99 0x1e, 0x1c, 0x00, 0x00, 0x1a,
100 0x20, 0x28, 0x25, 0x24, 0x26,
101 0x15, 0x13, 0x11, 0x18, 0x1e,
102 0x1c, 0x00);
103 dsi_generic_write_seq(dsi, R69328_GAMMA_SET_B, 0x00,
104 0x1a, 0x20, 0x28, 0x25, 0x24,
105 0x26, 0x15, 0x13, 0x11, 0x18,
106 0x1e, 0x1c, 0x00, 0x00, 0x1a,
107 0x20, 0x28, 0x25, 0x24, 0x26,
108 0x15, 0x13, 0x11, 0x18, 0x1e,
109 0x1c, 0x00);
110 dsi_generic_write_seq(dsi, R69328_GAMMA_SET_C, 0x00,
111 0x1a, 0x20, 0x28, 0x25, 0x24,
112 0x26, 0x15, 0x13, 0x11, 0x18,
113 0x1e, 0x1c, 0x00, 0x00, 0x1a,
114 0x20, 0x28, 0x25, 0x24, 0x26,
115 0x15, 0x13, 0x11, 0x18, 0x1e,
116 0x1c, 0x00);
117
118 /* MACP On */
119 dsi_generic_write_seq(dsi, R69328_MACP, 0x03);
120
121 ret = mipi_dsi_dcs_set_display_on(dsi);
122 if (ret < 0) {
123 log_err("failed to set display on: %d\n", ret);
124 return ret;
125 }
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300126 mdelay(50);
127
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200128 return 0;
129}
130
131static int renesas_r69328_set_backlight(struct udevice *dev, int percent)
132{
133 struct renesas_r69328_priv *priv = dev_get_priv(dev);
134 int ret;
135
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300136 ret = backlight_enable(priv->backlight);
137 if (ret)
138 return ret;
139
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200140 mdelay(5);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300141
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200142 return backlight_set_brightness(priv->backlight, percent);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300143}
144
145static int renesas_r69328_timings(struct udevice *dev,
146 struct display_timing *timing)
147{
148 memcpy(timing, &default_timing, sizeof(*timing));
149 return 0;
150}
151
152static int renesas_r69328_of_to_plat(struct udevice *dev)
153{
154 struct renesas_r69328_priv *priv = dev_get_priv(dev);
155 int ret;
156
157 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
158 "backlight", &priv->backlight);
159 if (ret) {
160 log_err("cannot get backlight: ret = %d\n", ret);
161 return ret;
162 }
163
Svyatoslav Ryhelb600fa82025-03-04 21:29:01 +0200164 ret = device_get_supply_regulator(dev, "vdd-supply", &priv->vdd);
165 if (ret) {
166 log_err("Cannot get vdd-supply: ret = %d\n", ret);
167 return ret;
168 }
169
170 ret = device_get_supply_regulator(dev, "vddio-supply", &priv->vddio);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300171 if (ret) {
Svyatoslav Ryhelb600fa82025-03-04 21:29:01 +0200172 log_err("Cannot get vddio-supply: ret = %d\n", ret);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300173 return ret;
174 }
175
176 ret = gpio_request_by_name(dev, "reset-gpios", 0,
177 &priv->reset_gpio, GPIOD_IS_OUT);
178 if (ret) {
179 log_err("could not decode reser-gpios (%d)\n", ret);
180 return ret;
181 }
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200182
183 return 0;
184}
185
186static int renesas_r69328_hw_init(struct udevice *dev)
187{
188 struct renesas_r69328_priv *priv = dev_get_priv(dev);
189 int ret;
190
Svyatoslav Ryhelb600fa82025-03-04 21:29:01 +0200191 ret = regulator_set_enable_if_allowed(priv->vddio, 1);
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200192 if (ret) {
Svyatoslav Ryhelb600fa82025-03-04 21:29:01 +0200193 log_debug("%s: enabling vddio-supply failed (%d)\n",
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200194 __func__, ret);
195 return ret;
196 }
197 mdelay(5);
198
Svyatoslav Ryhelb600fa82025-03-04 21:29:01 +0200199 ret = regulator_set_enable_if_allowed(priv->vdd, 1);
200 if (ret) {
201 log_debug("%s: enabling vdd-supply failed (%d)\n",
202 __func__, ret);
203 return ret;
204 }
205
Svyatoslav Ryhel8cd55462025-03-04 21:22:04 +0200206 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200207 if (ret) {
Svyatoslav Ryhel8cd55462025-03-04 21:22:04 +0200208 log_debug("%s: error entering reset (%d)\n",
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200209 __func__, ret);
210 return ret;
211 }
212 mdelay(5);
213
Svyatoslav Ryhel8cd55462025-03-04 21:22:04 +0200214 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200215 if (ret) {
Svyatoslav Ryhel8cd55462025-03-04 21:22:04 +0200216 log_debug("%s: error exiting reset (%d)\n",
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200217 __func__, ret);
218 return ret;
219 }
220
221 mdelay(5);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300222
223 return 0;
224}
225
226static int renesas_r69328_probe(struct udevice *dev)
227{
228 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
229
230 /* fill characteristics of DSI data link */
231 plat->lanes = 4;
232 plat->format = MIPI_DSI_FMT_RGB888;
Svyatoslav Ryhelbc575e92025-02-21 16:08:10 +0200233 plat->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
234 MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300235
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200236 return renesas_r69328_hw_init(dev);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300237}
238
239static const struct panel_ops renesas_r69328_ops = {
240 .enable_backlight = renesas_r69328_enable_backlight,
241 .set_backlight = renesas_r69328_set_backlight,
242 .get_display_timing = renesas_r69328_timings,
243};
244
245static const struct udevice_id renesas_r69328_ids[] = {
246 { .compatible = "jdi,dx12d100vm0eaa" },
247 { }
248};
249
250U_BOOT_DRIVER(renesas_r69328) = {
251 .name = "renesas_r69328",
252 .id = UCLASS_PANEL,
253 .of_match = renesas_r69328_ids,
254 .ops = &renesas_r69328_ops,
255 .of_to_plat = renesas_r69328_of_to_plat,
256 .probe = renesas_r69328_probe,
257 .plat_auto = sizeof(struct mipi_dsi_panel_plat),
258 .priv_auto = sizeof(struct renesas_r69328_priv),
259};