xref: /linux/drivers/gpu/drm/panel/panel-startek-kd070fhfid015.c (revision e7d759f31ca295d589f7420719c311870bb3166f)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2016 InforceComputing
4  * Copyright (C) 2016 Linaro Ltd
5  * Copyright (C) 2023 BayLibre, SAS
6  *
7  * Authors:
8  * - Vinay Simha BN <simhavcs@gmail.com>
9  * - Sumit Semwal <sumit.semwal@linaro.org>
10  * - Guillaume La Roque <glaroque@baylibre.com>
11  *
12  */
13 
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/module.h>
18 #include <linux/of.h>
19 #include <linux/regulator/consumer.h>
20 
21 #include <video/mipi_display.h>
22 
23 #include <drm/drm_mipi_dsi.h>
24 #include <drm/drm_modes.h>
25 #include <drm/drm_panel.h>
26 
27 #define DSI_REG_MCAP	0xB0
28 #define DSI_REG_IS	0xB3 /* Interface Setting */
29 #define DSI_REG_IIS	0xB4 /* Interface ID Setting */
30 #define DSI_REG_CTRL	0xB6
31 
32 enum {
33 	IOVCC = 0,
34 	POWER = 1
35 };
36 
37 struct stk_panel {
38 	const struct drm_display_mode *mode;
39 	struct backlight_device *backlight;
40 	struct drm_panel base;
41 	struct gpio_desc *enable_gpio; /* Power IC supply enable */
42 	struct gpio_desc *reset_gpio; /* External reset */
43 	struct mipi_dsi_device *dsi;
44 	struct regulator_bulk_data supplies[2];
45 };
46 
47 static inline struct stk_panel *to_stk_panel(struct drm_panel *panel)
48 {
49 	return container_of(panel, struct stk_panel, base);
50 }
51 
52 static int stk_panel_init(struct stk_panel *stk)
53 {
54 	struct mipi_dsi_device *dsi = stk->dsi;
55 	struct device *dev = &stk->dsi->dev;
56 	int ret;
57 
58 	ret = mipi_dsi_dcs_soft_reset(dsi);
59 	if (ret < 0) {
60 		dev_err(dev, "failed to mipi_dsi_dcs_soft_reset: %d\n", ret);
61 		return ret;
62 	}
63 	mdelay(5);
64 
65 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
66 	if (ret < 0) {
67 		dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
68 		return ret;
69 	}
70 	msleep(120);
71 
72 	mipi_dsi_generic_write_seq(dsi, DSI_REG_MCAP, 0x04);
73 
74 	/* Interface setting, video mode */
75 	mipi_dsi_generic_write_seq(dsi, DSI_REG_IS, 0x14, 0x08, 0x00, 0x22, 0x00);
76 	mipi_dsi_generic_write_seq(dsi, DSI_REG_IIS, 0x0C, 0x00);
77 	mipi_dsi_generic_write_seq(dsi, DSI_REG_CTRL, 0x3A, 0xD3);
78 
79 	ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x77);
80 	if (ret < 0) {
81 		dev_err(dev, "failed to write display brightness: %d\n", ret);
82 		return ret;
83 	}
84 
85 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
86 			       MIPI_DCS_WRITE_MEMORY_START);
87 
88 	ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77);
89 	if (ret < 0) {
90 		dev_err(dev, "failed to set pixel format: %d\n", ret);
91 		return ret;
92 	}
93 
94 	ret = mipi_dsi_dcs_set_column_address(dsi, 0, stk->mode->hdisplay - 1);
95 	if (ret < 0) {
96 		dev_err(dev, "failed to set column address: %d\n", ret);
97 		return ret;
98 	}
99 
100 	ret = mipi_dsi_dcs_set_page_address(dsi, 0, stk->mode->vdisplay - 1);
101 	if (ret < 0) {
102 		dev_err(dev, "failed to set page address: %d\n", ret);
103 		return ret;
104 	}
105 
106 	return 0;
107 }
108 
109 static int stk_panel_on(struct stk_panel *stk)
110 {
111 	struct mipi_dsi_device *dsi = stk->dsi;
112 	struct device *dev = &stk->dsi->dev;
113 	int ret;
114 
115 	ret = mipi_dsi_dcs_set_display_on(dsi);
116 	if (ret < 0)
117 		dev_err(dev, "failed to set display on: %d\n", ret);
118 
119 	mdelay(20);
120 
121 	return ret;
122 }
123 
124 static void stk_panel_off(struct stk_panel *stk)
125 {
126 	struct mipi_dsi_device *dsi = stk->dsi;
127 	struct device *dev = &stk->dsi->dev;
128 	int ret;
129 
130 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
131 
132 	ret = mipi_dsi_dcs_set_display_off(dsi);
133 	if (ret < 0)
134 		dev_err(dev, "failed to set display off: %d\n", ret);
135 
136 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
137 	if (ret < 0)
138 		dev_err(dev, "failed to enter sleep mode: %d\n", ret);
139 
140 	msleep(100);
141 }
142 
143 static int stk_panel_unprepare(struct drm_panel *panel)
144 {
145 	struct stk_panel *stk = to_stk_panel(panel);
146 
147 	stk_panel_off(stk);
148 	regulator_bulk_disable(ARRAY_SIZE(stk->supplies), stk->supplies);
149 	gpiod_set_value(stk->reset_gpio, 0);
150 	gpiod_set_value(stk->enable_gpio, 1);
151 
152 	return 0;
153 }
154 
155 static int stk_panel_prepare(struct drm_panel *panel)
156 {
157 	struct stk_panel *stk = to_stk_panel(panel);
158 	struct device *dev = &stk->dsi->dev;
159 	int ret;
160 
161 	gpiod_set_value(stk->reset_gpio, 0);
162 	gpiod_set_value(stk->enable_gpio, 0);
163 	ret = regulator_enable(stk->supplies[IOVCC].consumer);
164 	if (ret < 0)
165 		return ret;
166 
167 	mdelay(8);
168 	ret = regulator_enable(stk->supplies[POWER].consumer);
169 	if (ret < 0)
170 		goto iovccoff;
171 
172 	mdelay(20);
173 	gpiod_set_value(stk->enable_gpio, 1);
174 	mdelay(20);
175 	gpiod_set_value(stk->reset_gpio, 1);
176 	mdelay(10);
177 	ret = stk_panel_init(stk);
178 	if (ret < 0) {
179 		dev_err(dev, "failed to init panel: %d\n", ret);
180 		goto poweroff;
181 	}
182 
183 	ret = stk_panel_on(stk);
184 	if (ret < 0) {
185 		dev_err(dev, "failed to set panel on: %d\n", ret);
186 		goto poweroff;
187 	}
188 
189 	return 0;
190 
191 poweroff:
192 	regulator_disable(stk->supplies[POWER].consumer);
193 iovccoff:
194 	regulator_disable(stk->supplies[IOVCC].consumer);
195 	gpiod_set_value(stk->reset_gpio, 0);
196 	gpiod_set_value(stk->enable_gpio, 0);
197 
198 	return ret;
199 }
200 
201 static const struct drm_display_mode default_mode = {
202 		.clock = 163204,
203 		.hdisplay = 1200,
204 		.hsync_start = 1200 + 144,
205 		.hsync_end = 1200 + 144 + 16,
206 		.htotal = 1200 + 144 + 16 + 45,
207 		.vdisplay = 1920,
208 		.vsync_start = 1920 + 8,
209 		.vsync_end = 1920 + 8 + 4,
210 		.vtotal = 1920 + 8 + 4 + 4,
211 		.width_mm = 95,
212 		.height_mm = 151,
213 };
214 
215 static int stk_panel_get_modes(struct drm_panel *panel,
216 			       struct drm_connector *connector)
217 {
218 	struct drm_display_mode *mode;
219 
220 	mode = drm_mode_duplicate(connector->dev, &default_mode);
221 	if (!mode) {
222 		dev_err(panel->dev, "failed to add mode %ux%ux@%u\n",
223 			default_mode.hdisplay, default_mode.vdisplay,
224 			drm_mode_vrefresh(&default_mode));
225 		return -ENOMEM;
226 	}
227 
228 	drm_mode_set_name(mode);
229 	drm_mode_probed_add(connector, mode);
230 	connector->display_info.width_mm = default_mode.width_mm;
231 	connector->display_info.height_mm = default_mode.height_mm;
232 	return 1;
233 }
234 
235 static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
236 {
237 	struct mipi_dsi_device *dsi = bl_get_data(bl);
238 	int ret;
239 	u16 brightness;
240 
241 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
242 	ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
243 	if (ret < 0)
244 		return ret;
245 
246 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
247 	return brightness & 0xff;
248 }
249 
250 static int dsi_dcs_bl_update_status(struct backlight_device *bl)
251 {
252 	struct mipi_dsi_device *dsi = bl_get_data(bl);
253 	struct device *dev = &dsi->dev;
254 	int ret;
255 
256 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
257 	ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
258 	if (ret < 0) {
259 		dev_err(dev, "failed to set DSI control: %d\n", ret);
260 		return ret;
261 	}
262 
263 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
264 	return 0;
265 }
266 
267 static const struct backlight_ops dsi_bl_ops = {
268 	.update_status = dsi_dcs_bl_update_status,
269 	.get_brightness = dsi_dcs_bl_get_brightness,
270 };
271 
272 static struct backlight_device *
273 drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
274 {
275 	struct device *dev = &dsi->dev;
276 	struct backlight_properties props = {
277 		.type = BACKLIGHT_RAW,
278 		.brightness = 255,
279 		.max_brightness = 255,
280 	};
281 
282 	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
283 					      &dsi_bl_ops, &props);
284 }
285 
286 static const struct drm_panel_funcs stk_panel_funcs = {
287 	.unprepare = stk_panel_unprepare,
288 	.prepare = stk_panel_prepare,
289 	.get_modes = stk_panel_get_modes,
290 };
291 
292 static const struct of_device_id stk_of_match[] = {
293 	{ .compatible = "startek,kd070fhfid015", },
294 	{ }
295 };
296 MODULE_DEVICE_TABLE(of, stk_of_match);
297 
298 static int stk_panel_add(struct stk_panel *stk)
299 {
300 	struct device *dev = &stk->dsi->dev;
301 	int ret;
302 
303 	stk->mode = &default_mode;
304 
305 	stk->supplies[IOVCC].supply = "iovcc";
306 	stk->supplies[POWER].supply = "power";
307 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(stk->supplies), stk->supplies);
308 	if (ret) {
309 		dev_err(dev, "regulator_bulk failed\n");
310 		return ret;
311 	}
312 
313 	stk->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
314 	if (IS_ERR(stk->reset_gpio)) {
315 		ret = PTR_ERR(stk->reset_gpio);
316 		dev_err(dev, "cannot get reset-gpios %d\n", ret);
317 		return ret;
318 	}
319 
320 	stk->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
321 	if (IS_ERR(stk->enable_gpio)) {
322 		ret = PTR_ERR(stk->enable_gpio);
323 		dev_err(dev, "cannot get enable-gpio %d\n", ret);
324 		return ret;
325 	}
326 
327 	stk->backlight = drm_panel_create_dsi_backlight(stk->dsi);
328 	if (IS_ERR(stk->backlight)) {
329 		ret = PTR_ERR(stk->backlight);
330 		dev_err(dev, "failed to register backlight %d\n", ret);
331 		return ret;
332 	}
333 
334 	drm_panel_init(&stk->base, &stk->dsi->dev, &stk_panel_funcs,
335 		       DRM_MODE_CONNECTOR_DSI);
336 
337 	drm_panel_add(&stk->base);
338 
339 	return 0;
340 }
341 
342 static int stk_panel_probe(struct mipi_dsi_device *dsi)
343 {
344 	struct stk_panel *stk;
345 	int ret;
346 
347 	dsi->lanes = 4;
348 	dsi->format = MIPI_DSI_FMT_RGB888;
349 	dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM);
350 
351 	stk = devm_kzalloc(&dsi->dev, sizeof(*stk), GFP_KERNEL);
352 	if (!stk)
353 		return -ENOMEM;
354 
355 	mipi_dsi_set_drvdata(dsi, stk);
356 
357 	stk->dsi = dsi;
358 
359 	ret = stk_panel_add(stk);
360 	if (ret < 0)
361 		return ret;
362 
363 	ret = mipi_dsi_attach(dsi);
364 	if (ret < 0)
365 		drm_panel_remove(&stk->base);
366 
367 	return 0;
368 }
369 
370 static void stk_panel_remove(struct mipi_dsi_device *dsi)
371 {
372 	struct stk_panel *stk = mipi_dsi_get_drvdata(dsi);
373 	int err;
374 
375 	err = mipi_dsi_detach(dsi);
376 	if (err < 0)
377 		dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
378 			err);
379 
380 	drm_panel_remove(&stk->base);
381 }
382 
383 static struct mipi_dsi_driver stk_panel_driver = {
384 	.driver = {
385 		.name = "panel-startek-kd070fhfid015",
386 		.of_match_table = stk_of_match,
387 	},
388 	.probe = stk_panel_probe,
389 	.remove = stk_panel_remove,
390 };
391 module_mipi_dsi_driver(stk_panel_driver);
392 
393 MODULE_AUTHOR("Guillaume La Roque <glaroque@baylibre.com>");
394 MODULE_DESCRIPTION("STARTEK KD070FHFID015");
395 MODULE_LICENSE("GPL");
396