blob: 9861c3fef11acc697574d54cebdaf49cb6d236e0 [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 {
35 struct udevice *backlight;
36
37 struct gpio_desc enable_gpio;
38 struct gpio_desc reset_gpio;
39};
40
41static const u8 address_mode[] = {
42 MIPI_DCS_SET_ADDRESS_MODE
43};
44
45#define dsi_generic_write_seq(dsi, cmd, seq...) do { \
46 static const u8 b[] = { cmd, seq }; \
47 int ret; \
48 ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
49 if (ret < 0) \
50 return ret; \
51 } while (0)
52
53static struct display_timing default_timing = {
54 .pixelclock.typ = 68000000,
55 .hactive.typ = 720,
56 .hfront_porch.typ = 92,
57 .hback_porch.typ = 62,
58 .hsync_len.typ = 4,
59 .vactive.typ = 1280,
60 .vfront_porch.typ = 6,
61 .vback_porch.typ = 3,
62 .vsync_len.typ = 1,
63};
64
65static int renesas_r69328_enable_backlight(struct udevice *dev)
66{
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +030067 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
68 struct mipi_dsi_device *dsi = plat->device;
69 int ret;
70
71 mipi_dsi_dcs_write_buffer(dsi, address_mode,
72 sizeof(address_mode));
73
74 ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
75 if (ret < 0) {
76 log_err("failed to set pixel format: %d\n", ret);
77 return ret;
78 }
79
80 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
81 if (ret < 0) {
82 log_err("failed to exit sleep mode: %d\n", ret);
83 return ret;
84 }
85
86 mdelay(100);
87
88 /* MACP Off */
89 dsi_generic_write_seq(dsi, R69328_MACP, 0x04);
90
91 dsi_generic_write_seq(dsi, R69328_POWER_SET, 0x14,
92 0x1d, 0x21, 0x67, 0x11, 0x9a);
93
94 dsi_generic_write_seq(dsi, R69328_GAMMA_SET_A, 0x00,
95 0x1a, 0x20, 0x28, 0x25, 0x24,
96 0x26, 0x15, 0x13, 0x11, 0x18,
97 0x1e, 0x1c, 0x00, 0x00, 0x1a,
98 0x20, 0x28, 0x25, 0x24, 0x26,
99 0x15, 0x13, 0x11, 0x18, 0x1e,
100 0x1c, 0x00);
101 dsi_generic_write_seq(dsi, R69328_GAMMA_SET_B, 0x00,
102 0x1a, 0x20, 0x28, 0x25, 0x24,
103 0x26, 0x15, 0x13, 0x11, 0x18,
104 0x1e, 0x1c, 0x00, 0x00, 0x1a,
105 0x20, 0x28, 0x25, 0x24, 0x26,
106 0x15, 0x13, 0x11, 0x18, 0x1e,
107 0x1c, 0x00);
108 dsi_generic_write_seq(dsi, R69328_GAMMA_SET_C, 0x00,
109 0x1a, 0x20, 0x28, 0x25, 0x24,
110 0x26, 0x15, 0x13, 0x11, 0x18,
111 0x1e, 0x1c, 0x00, 0x00, 0x1a,
112 0x20, 0x28, 0x25, 0x24, 0x26,
113 0x15, 0x13, 0x11, 0x18, 0x1e,
114 0x1c, 0x00);
115
116 /* MACP On */
117 dsi_generic_write_seq(dsi, R69328_MACP, 0x03);
118
119 ret = mipi_dsi_dcs_set_display_on(dsi);
120 if (ret < 0) {
121 log_err("failed to set display on: %d\n", ret);
122 return ret;
123 }
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300124 mdelay(50);
125
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200126 return 0;
127}
128
129static int renesas_r69328_set_backlight(struct udevice *dev, int percent)
130{
131 struct renesas_r69328_priv *priv = dev_get_priv(dev);
132 int ret;
133
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300134 ret = backlight_enable(priv->backlight);
135 if (ret)
136 return ret;
137
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200138 mdelay(5);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300139
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200140 return backlight_set_brightness(priv->backlight, percent);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300141}
142
143static int renesas_r69328_timings(struct udevice *dev,
144 struct display_timing *timing)
145{
146 memcpy(timing, &default_timing, sizeof(*timing));
147 return 0;
148}
149
150static int renesas_r69328_of_to_plat(struct udevice *dev)
151{
152 struct renesas_r69328_priv *priv = dev_get_priv(dev);
153 int ret;
154
155 ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
156 "backlight", &priv->backlight);
157 if (ret) {
158 log_err("cannot get backlight: ret = %d\n", ret);
159 return ret;
160 }
161
162 ret = gpio_request_by_name(dev, "enable-gpios", 0,
163 &priv->enable_gpio, GPIOD_IS_OUT);
164 if (ret) {
165 log_err("could not decode enable-gpios (%d)\n", ret);
166 return ret;
167 }
168
169 ret = gpio_request_by_name(dev, "reset-gpios", 0,
170 &priv->reset_gpio, GPIOD_IS_OUT);
171 if (ret) {
172 log_err("could not decode reser-gpios (%d)\n", ret);
173 return ret;
174 }
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200175
176 return 0;
177}
178
179static int renesas_r69328_hw_init(struct udevice *dev)
180{
181 struct renesas_r69328_priv *priv = dev_get_priv(dev);
182 int ret;
183
184 ret = dm_gpio_set_value(&priv->enable_gpio, 1);
185 if (ret) {
186 log_debug("%s: error changing enable-gpios (%d)\n",
187 __func__, ret);
188 return ret;
189 }
190 mdelay(5);
191
192 ret = dm_gpio_set_value(&priv->reset_gpio, 0);
193 if (ret) {
194 log_debug("%s: error changing reset-gpios (%d)\n",
195 __func__, ret);
196 return ret;
197 }
198 mdelay(5);
199
200 ret = dm_gpio_set_value(&priv->reset_gpio, 1);
201 if (ret) {
202 log_debug("%s: error changing reset-gpios (%d)\n",
203 __func__, ret);
204 return ret;
205 }
206
207 mdelay(5);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300208
209 return 0;
210}
211
212static int renesas_r69328_probe(struct udevice *dev)
213{
214 struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
215
216 /* fill characteristics of DSI data link */
217 plat->lanes = 4;
218 plat->format = MIPI_DSI_FMT_RGB888;
219 plat->mode_flags = MIPI_DSI_MODE_VIDEO;
220
Svyatoslav Ryhel8a13fd22024-01-31 08:57:21 +0200221 return renesas_r69328_hw_init(dev);
Svyatoslav Ryhelfcbbd562023-04-25 10:51:45 +0300222}
223
224static const struct panel_ops renesas_r69328_ops = {
225 .enable_backlight = renesas_r69328_enable_backlight,
226 .set_backlight = renesas_r69328_set_backlight,
227 .get_display_timing = renesas_r69328_timings,
228};
229
230static const struct udevice_id renesas_r69328_ids[] = {
231 { .compatible = "jdi,dx12d100vm0eaa" },
232 { }
233};
234
235U_BOOT_DRIVER(renesas_r69328) = {
236 .name = "renesas_r69328",
237 .id = UCLASS_PANEL,
238 .of_match = renesas_r69328_ids,
239 .ops = &renesas_r69328_ops,
240 .of_to_plat = renesas_r69328_of_to_plat,
241 .probe = renesas_r69328_probe,
242 .plat_auto = sizeof(struct mipi_dsi_panel_plat),
243 .priv_auto = sizeof(struct renesas_r69328_priv),
244};