xref: /linux/drivers/gpu/drm/panel/panel-renesas-r69328.c (revision fbf5df34a4dbcd09d433dd4f0916bf9b2ddb16de)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/array_size.h>
4 #include <linux/delay.h>
5 #include <linux/err.h>
6 #include <linux/gpio/consumer.h>
7 #include <linux/mod_devicetable.h>
8 #include <linux/module.h>
9 #include <linux/property.h>
10 #include <linux/regulator/consumer.h>
11 
12 #include <video/mipi_display.h>
13 
14 #include <drm/drm_mipi_dsi.h>
15 #include <drm/drm_modes.h>
16 #include <drm/drm_panel.h>
17 #include <drm/drm_probe_helper.h>
18 
19 #define R69328_MACP		0xb0 /* Manufacturer Access CMD Protect */
20 #define   R69328_MACP_ON	0x03
21 #define   R69328_MACP_OFF	0x04
22 
23 #define R69328_GAMMA_SET_A	0xc8 /* Gamma Setting A */
24 #define R69328_GAMMA_SET_B	0xc9 /* Gamma Setting B */
25 #define R69328_GAMMA_SET_C	0xca /* Gamma Setting C */
26 
27 #define R69328_POWER_SET	0xd1
28 
29 struct renesas_r69328 {
30 	struct drm_panel panel;
31 	struct mipi_dsi_device *dsi;
32 
33 	struct regulator *vdd_supply;
34 	struct regulator *vddio_supply;
35 	struct gpio_desc *reset_gpio;
36 };
37 
38 static inline struct renesas_r69328 *to_renesas_r69328(struct drm_panel *panel)
39 {
40 	return container_of(panel, struct renesas_r69328, panel);
41 }
42 
43 static void renesas_r69328_reset(struct renesas_r69328 *priv)
44 {
45 	gpiod_set_value_cansleep(priv->reset_gpio, 1);
46 	usleep_range(10000, 11000);
47 	gpiod_set_value_cansleep(priv->reset_gpio, 0);
48 	usleep_range(2000, 3000);
49 }
50 
51 static int renesas_r69328_prepare(struct drm_panel *panel)
52 {
53 	struct renesas_r69328 *priv = to_renesas_r69328(panel);
54 	struct device *dev = &priv->dsi->dev;
55 	int ret;
56 
57 	ret = regulator_enable(priv->vdd_supply);
58 	if (ret) {
59 		dev_err(dev, "failed to enable vdd power supply\n");
60 		return ret;
61 	}
62 
63 	usleep_range(10000, 11000);
64 
65 	ret = regulator_enable(priv->vddio_supply);
66 	if (ret < 0) {
67 		dev_err(dev, "failed to enable vddio power supply\n");
68 		return ret;
69 	}
70 
71 	usleep_range(10000, 11000);
72 
73 	renesas_r69328_reset(priv);
74 
75 	return 0;
76 }
77 
78 static int renesas_r69328_enable(struct drm_panel *panel)
79 {
80 	struct renesas_r69328 *priv = to_renesas_r69328(panel);
81 	struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
82 
83 	/* Set address mode */
84 	mipi_dsi_dcs_write_seq_multi(&ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00);
85 	mipi_dsi_dcs_set_pixel_format_multi(&ctx, MIPI_DCS_PIXEL_FMT_24BIT << 4);
86 	mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
87 
88 	mipi_dsi_msleep(&ctx, 100);
89 
90 	/* MACP Off */
91 	mipi_dsi_generic_write_seq_multi(&ctx, R69328_MACP, R69328_MACP_OFF);
92 
93 	mipi_dsi_generic_write_seq_multi(&ctx, R69328_POWER_SET, 0x14, 0x1d,
94 					 0x21, 0x67, 0x11, 0x9a);
95 
96 	mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_A, 0x00, 0x1a,
97 					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
98 					 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a,
99 					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
100 					 0x11, 0x18, 0x1e, 0x1c, 0x00);
101 
102 	mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_B, 0x00, 0x1a,
103 					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
104 					 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a,
105 					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
106 					 0x11, 0x18, 0x1e, 0x1c, 0x00);
107 
108 	mipi_dsi_generic_write_seq_multi(&ctx, R69328_GAMMA_SET_C, 0x00, 0x1a,
109 					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
110 					 0x11, 0x18, 0x1e, 0x1c, 0x00, 0x00, 0x1a,
111 					 0x20, 0x28, 0x25, 0x24, 0x26, 0x15, 0x13,
112 					 0x11, 0x18, 0x1e, 0x1c, 0x00);
113 
114 	/* MACP On */
115 	mipi_dsi_generic_write_seq_multi(&ctx, R69328_MACP, R69328_MACP_ON);
116 
117 	mipi_dsi_dcs_set_display_on_multi(&ctx);
118 	mipi_dsi_msleep(&ctx, 50);
119 
120 	return ctx.accum_err;
121 }
122 
123 static int renesas_r69328_disable(struct drm_panel *panel)
124 {
125 	struct renesas_r69328 *priv = to_renesas_r69328(panel);
126 	struct mipi_dsi_multi_context ctx = { .dsi = priv->dsi };
127 
128 	mipi_dsi_dcs_set_display_off_multi(&ctx);
129 	mipi_dsi_msleep(&ctx, 60);
130 	mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
131 
132 	return ctx.accum_err;
133 }
134 
135 static int renesas_r69328_unprepare(struct drm_panel *panel)
136 {
137 	struct renesas_r69328 *priv = to_renesas_r69328(panel);
138 
139 	gpiod_set_value_cansleep(priv->reset_gpio, 1);
140 
141 	usleep_range(5000, 6000);
142 
143 	regulator_disable(priv->vddio_supply);
144 	regulator_disable(priv->vdd_supply);
145 
146 	return 0;
147 }
148 
149 static const struct drm_display_mode renesas_r69328_mode = {
150 	.clock = (720 + 92 + 62 + 4) * (1280 + 6 + 3 + 1) * 60 / 1000,
151 	.hdisplay = 720,
152 	.hsync_start = 720 + 92,
153 	.hsync_end = 720 + 92 + 62,
154 	.htotal = 720 + 92 + 62 + 4,
155 	.vdisplay = 1280,
156 	.vsync_start = 1280 + 6,
157 	.vsync_end = 1280 + 6 + 3,
158 	.vtotal = 1280 + 6 + 3 + 1,
159 	.width_mm = 59,
160 	.height_mm = 105,
161 	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
162 };
163 
164 static int renesas_r69328_get_modes(struct drm_panel *panel,
165 				    struct drm_connector *connector)
166 {
167 	return drm_connector_helper_get_modes_fixed(connector, &renesas_r69328_mode);
168 }
169 
170 static const struct drm_panel_funcs renesas_r69328_panel_funcs = {
171 	.prepare = renesas_r69328_prepare,
172 	.enable = renesas_r69328_enable,
173 	.disable = renesas_r69328_disable,
174 	.unprepare = renesas_r69328_unprepare,
175 	.get_modes = renesas_r69328_get_modes,
176 };
177 
178 static int renesas_r69328_probe(struct mipi_dsi_device *dsi)
179 {
180 	struct device *dev = &dsi->dev;
181 	struct renesas_r69328 *priv;
182 	int ret;
183 
184 	priv = devm_drm_panel_alloc(dev, struct renesas_r69328, panel,
185 				    &renesas_r69328_panel_funcs,
186 				    DRM_MODE_CONNECTOR_DSI);
187 	if (IS_ERR(priv))
188 		return PTR_ERR(priv);
189 
190 	priv->vdd_supply = devm_regulator_get(dev, "vdd");
191 	if (IS_ERR(priv->vdd_supply))
192 		return dev_err_probe(dev, PTR_ERR(priv->vdd_supply),
193 				     "Failed to get vdd-supply\n");
194 
195 	priv->vddio_supply = devm_regulator_get(dev, "vddio");
196 	if (IS_ERR(priv->vddio_supply))
197 		return dev_err_probe(dev, PTR_ERR(priv->vddio_supply),
198 				     "Failed to get vddio-supply\n");
199 
200 	priv->reset_gpio = devm_gpiod_get_optional(dev, "reset",
201 						   GPIOD_OUT_LOW);
202 	if (IS_ERR(priv->reset_gpio))
203 		return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
204 				     "Failed to get reset-gpios\n");
205 
206 	priv->dsi = dsi;
207 	mipi_dsi_set_drvdata(dsi, priv);
208 
209 	dsi->lanes = 4;
210 	dsi->format = MIPI_DSI_FMT_RGB888;
211 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
212 			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
213 
214 	ret = drm_panel_of_backlight(&priv->panel);
215 	if (ret)
216 		return dev_err_probe(dev, ret, "Failed to get backlight\n");
217 
218 	drm_panel_add(&priv->panel);
219 
220 	ret = devm_mipi_dsi_attach(dev, dsi);
221 	if (ret) {
222 		drm_panel_remove(&priv->panel);
223 		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
224 	}
225 
226 	return 0;
227 }
228 
229 static void renesas_r69328_remove(struct mipi_dsi_device *dsi)
230 {
231 	struct renesas_r69328 *priv = mipi_dsi_get_drvdata(dsi);
232 
233 	drm_panel_remove(&priv->panel);
234 }
235 
236 static const struct of_device_id renesas_r69328_of_match[] = {
237 	{ .compatible = "jdi,dx12d100vm0eaa" },
238 	{ /* sentinel */ }
239 };
240 MODULE_DEVICE_TABLE(of, renesas_r69328_of_match);
241 
242 static struct mipi_dsi_driver renesas_r69328_driver = {
243 	.probe = renesas_r69328_probe,
244 	.remove = renesas_r69328_remove,
245 	.driver = {
246 		.name = "panel-renesas-r69328",
247 		.of_match_table = renesas_r69328_of_match,
248 	},
249 };
250 module_mipi_dsi_driver(renesas_r69328_driver);
251 
252 MODULE_AUTHOR("Maxim Schwalm <maxim.schwalm@gmail.com>");
253 MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
254 MODULE_DESCRIPTION("Renesas R69328-based panel driver");
255 MODULE_LICENSE("GPL");
256