xref: /linux/drivers/gpu/drm/panel/panel-ilitek-ili9488.c (revision 3a2c4d55e32ad65efebdb6de44eef3bfa08bb49d)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <linux/delay.h>
4 #include <linux/device.h>
5 #include <linux/err.h>
6 #include <linux/errno.h>
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 
11 #include <linux/gpio/consumer.h>
12 #include <linux/regulator/consumer.h>
13 
14 #include <drm/drm_mipi_dsi.h>
15 #include <drm/drm_modes.h>
16 #include <drm/drm_of.h>
17 #include <drm/drm_panel.h>
18 #include <drm/drm_probe_helper.h>
19 
20 #include <video/mipi_display.h>
21 
22 struct ili9488_desc {
23 	const struct drm_display_mode *display_mode;
24 	unsigned long mode_flags;
25 	enum mipi_dsi_pixel_format format;
26 	unsigned int lanes;
27 	unsigned int bpc;
28 	void (*init_sequence)(struct mipi_dsi_multi_context *ctx);
29 };
30 
31 struct ili9488 {
32 	struct drm_panel panel;
33 	struct mipi_dsi_device *dsi;
34 	struct gpio_desc *reset;
35 	struct regulator_bulk_data supplies[2];
36 	const struct ili9488_desc *desc;
37 	enum drm_panel_orientation orientation;
38 };
39 
40 static const char * const regulator_names[] = {
41 	"vci",
42 	"iovcc",
43 };
44 
45 static void e35gh_i_mw800cb_init(struct mipi_dsi_multi_context *ctx)
46 {
47 	/* Gamma control 1,2 */
48 	mipi_dsi_dcs_write_seq_multi(ctx, 0xE0, 0x00, 0x10, 0x14, 0x01, 0x0E, 0x04, 0x33,
49 				     0x56, 0x48, 0x03, 0x0C, 0x0B, 0x2B, 0x34, 0x0F);
50 	mipi_dsi_dcs_write_seq_multi(ctx, 0xE1, 0x00, 0x12, 0x18, 0x05, 0x12, 0x06, 0x40,
51 				     0x34, 0x57, 0x06, 0x10, 0x0C, 0x3B, 0x3F, 0x0F);
52 	/* Power control 1,2 */
53 	mipi_dsi_dcs_write_seq_multi(ctx, 0xC0, 0x0F, 0x0C);
54 	mipi_dsi_dcs_write_seq_multi(ctx, 0xC1, 0x41);
55 	/* VCOM Control */
56 	mipi_dsi_dcs_write_seq_multi(ctx, 0xC5, 0x00, 0x25, 0x80);
57 	mipi_dsi_dcs_write_seq_multi(ctx, 0x36, 0x48);
58 	/* Interface pixel format 18bpp */
59 	mipi_dsi_dcs_write_seq_multi(ctx, 0x3A, 0x66);
60 	mipi_dsi_dcs_write_seq_multi(ctx, 0xB0, 0x00);
61 	mipi_dsi_dcs_write_seq_multi(ctx, 0xB1, 0xA0);
62 	mipi_dsi_dcs_write_seq_multi(ctx, 0xB4, 0x02);
63 	mipi_dsi_dcs_write_seq_multi(ctx, 0xB6, 0x02, 0x02, 0x3B);
64 	mipi_dsi_dcs_write_seq_multi(ctx, 0xE9, 0x00);
65 	mipi_dsi_dcs_write_seq_multi(ctx, 0xF7, 0xA9, 0x51, 0x2C, 0x82);
66 	mipi_dsi_dcs_write_seq_multi(ctx, 0x21);
67 }
68 
69 static const struct drm_display_mode e35gh_i_mw800cb_display_mode = {
70 	.clock = 14400,
71 
72 	.hdisplay = 320,
73 	.hsync_start = 320 + 60,
74 	.hsync_end = 320 + 60 + 20,
75 	.htotal = 320 + 60 + 20 + 42,
76 
77 	.vdisplay = 480,
78 	.vsync_start = 480 + 20,
79 	.vsync_end = 480 + 20 + 10,
80 	.vtotal = 480 + 20 + 10 + 33,
81 
82 	.width_mm = 48,
83 	.height_mm = 73,
84 
85 	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
86 	.type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
87 };
88 
89 static inline struct ili9488 *panel_to_ili9488(struct drm_panel *panel)
90 {
91 	return container_of(panel, struct ili9488, panel);
92 }
93 
94 static int ili9488_power_on(struct ili9488 *ili)
95 {
96 	struct mipi_dsi_device *dsi = ili->dsi;
97 	int ret;
98 
99 	ret = regulator_bulk_enable(ARRAY_SIZE(ili->supplies), ili->supplies);
100 	if (ret < 0) {
101 		dev_err(&dsi->dev, "regulator bulk enable failed: %d\n", ret);
102 		return ret;
103 	}
104 
105 	gpiod_set_value_cansleep(ili->reset, 0);
106 	usleep_range(1000, 5000);
107 	gpiod_set_value_cansleep(ili->reset, 1);
108 	usleep_range(1000, 5000);
109 	gpiod_set_value_cansleep(ili->reset, 0);
110 	usleep_range(5000, 10000);
111 
112 	return 0;
113 }
114 
115 static int ili9488_power_off(struct ili9488 *ili)
116 {
117 	struct mipi_dsi_device *dsi = ili->dsi;
118 	int ret;
119 
120 	gpiod_set_value_cansleep(ili->reset, 1);
121 
122 	ret = regulator_bulk_disable(ARRAY_SIZE(ili->supplies), ili->supplies);
123 	if (ret)
124 		dev_err(&dsi->dev, "regulator bulk disable failed: %d\n", ret);
125 
126 	return ret;
127 }
128 
129 static int ili9488_activate(struct ili9488 *ili)
130 {
131 	struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi };
132 
133 	if (ili->desc->init_sequence)
134 		ili->desc->init_sequence(&ctx);
135 
136 	mipi_dsi_dcs_exit_sleep_mode_multi(&ctx);
137 	mipi_dsi_msleep(&ctx, 120);
138 	mipi_dsi_dcs_set_display_on_multi(&ctx);
139 
140 	return ctx.accum_err;
141 }
142 
143 static int ili9488_prepare(struct drm_panel *panel)
144 {
145 	struct ili9488 *ili = panel_to_ili9488(panel);
146 	int ret;
147 
148 	ret = ili9488_power_on(ili);
149 	if (ret)
150 		return ret;
151 
152 	ret = ili9488_activate(ili);
153 	if (ret) {
154 		ili9488_power_off(ili);
155 		return ret;
156 	}
157 
158 	return 0;
159 }
160 
161 static int ili9488_deactivate(struct ili9488 *ili)
162 {
163 	struct mipi_dsi_multi_context ctx = { .dsi = ili->dsi };
164 
165 	mipi_dsi_dcs_set_display_off_multi(&ctx);
166 	mipi_dsi_dcs_enter_sleep_mode_multi(&ctx);
167 	mipi_dsi_msleep(&ctx, 120);
168 
169 	return ctx.accum_err;
170 }
171 
172 static int ili9488_unprepare(struct drm_panel *panel)
173 {
174 	struct ili9488 *ili = panel_to_ili9488(panel);
175 	struct mipi_dsi_device *dsi = ili->dsi;
176 	int ret;
177 
178 	ili9488_deactivate(ili);
179 	ret = ili9488_power_off(ili);
180 	if (ret < 0)
181 		dev_err(&dsi->dev, "power off failed: %d\n", ret);
182 
183 	return ret;
184 }
185 
186 static int ili9488_get_modes(struct drm_panel *panel, struct drm_connector *connector)
187 {
188 	struct ili9488 *ili = panel_to_ili9488(panel);
189 	const struct drm_display_mode *mode = ili->desc->display_mode;
190 
191 	connector->display_info.bpc = ili->desc->bpc;
192 
193 	return drm_connector_helper_get_modes_fixed(connector, mode);
194 }
195 
196 static enum drm_panel_orientation ili9488_get_orientation(struct drm_panel *panel)
197 {
198 	struct ili9488 *ili = panel_to_ili9488(panel);
199 
200 	return ili->orientation;
201 }
202 
203 static const struct drm_panel_funcs ili9488_funcs = {
204 	.prepare	= ili9488_prepare,
205 	.unprepare	= ili9488_unprepare,
206 	.get_modes	= ili9488_get_modes,
207 	.get_orientation = ili9488_get_orientation,
208 };
209 
210 static int ili9488_dsi_probe(struct mipi_dsi_device *dsi)
211 {
212 	struct device *dev = &dsi->dev;
213 	struct ili9488 *ili;
214 	int i, ret;
215 
216 	ili = devm_drm_panel_alloc(dev, struct ili9488, panel, &ili9488_funcs,
217 				   DRM_MODE_CONNECTOR_DSI);
218 	if (IS_ERR(ili))
219 		return PTR_ERR(ili);
220 
221 	ili->desc = device_get_match_data(dev);
222 	ili->dsi = dsi;
223 
224 	dsi->mode_flags = ili->desc->mode_flags;
225 	dsi->format = ili->desc->format;
226 	dsi->lanes = ili->desc->lanes;
227 
228 	ili->reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
229 	if (IS_ERR(ili->reset))
230 		return dev_err_probe(dev, PTR_ERR(ili->reset),
231 				     "failed to get reset-gpios\n");
232 
233 	for (i = 0; i < ARRAY_SIZE(ili->supplies); i++)
234 		ili->supplies[i].supply = regulator_names[i];
235 
236 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ili->supplies),
237 				      ili->supplies);
238 	if (ret < 0)
239 		return dev_err_probe(dev, ret, "failed to get regulators\n");
240 
241 	ret = drm_of_get_panel_orientation(dev->of_node, &ili->orientation);
242 	if (ret)
243 		return dev_err_probe(dev, ret, "failed to get orientation\n");
244 
245 	ret = drm_panel_of_backlight(&ili->panel);
246 	if (ret)
247 		return dev_err_probe(dev, ret, "failed to get backlight\n");
248 
249 	ili->panel.prepare_prev_first = true;
250 
251 	ret = devm_drm_panel_add(dev, &ili->panel);
252 	if (ret)
253 		return ret;
254 
255 	ret = devm_mipi_dsi_attach(dev, dsi);
256 	if (ret < 0)
257 		return dev_err_probe(dev, ret, "failed to attach to DSI host\n");
258 
259 	return 0;
260 }
261 
262 static const struct ili9488_desc e35gh_i_mw800cb_desc = {
263 	.init_sequence = e35gh_i_mw800cb_init,
264 	.display_mode = &e35gh_i_mw800cb_display_mode,
265 	.mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
266 		      MIPI_DSI_MODE_LPM | MIPI_DSI_CLOCK_NON_CONTINUOUS,
267 	.format = MIPI_DSI_FMT_RGB666_PACKED,
268 	.lanes = 1,
269 	.bpc = 6,
270 };
271 
272 static const struct of_device_id ili9488_of_match[] = {
273 	{ .compatible = "focuslcds,e35gh-i-mw800cb", .data = &e35gh_i_mw800cb_desc },
274 	{ }
275 };
276 
277 MODULE_DEVICE_TABLE(of, ili9488_of_match);
278 
279 static struct mipi_dsi_driver ili9488_dsi_driver = {
280 	.probe	= ili9488_dsi_probe,
281 	.driver = {
282 		.name		= "ili9488-dsi",
283 		.of_match_table	= ili9488_of_match,
284 	},
285 };
286 module_mipi_dsi_driver(ili9488_dsi_driver);
287 
288 MODULE_AUTHOR("Igor Reznichenko <igor@reznichenko.net>");
289 MODULE_DESCRIPTION("Ilitek ILI9488 Controller Driver");
290 MODULE_LICENSE("GPL");
291