Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Mantix MLAF057WE51 5.7" MIPI-DSI panel driver
  4 *
  5 * Copyright (C) Purism SPC 2020
  6 */
  7
  8#include <linux/backlight.h>
  9#include <linux/delay.h>
 10#include <linux/gpio/consumer.h>
 11#include <linux/module.h>
 12#include <linux/of_device.h>
 13#include <linux/regulator/consumer.h>
 14
 15#include <video/mipi_display.h>
 16
 17#include <drm/drm_mipi_dsi.h>
 18#include <drm/drm_modes.h>
 19#include <drm/drm_panel.h>
 20
 21#define DRV_NAME "panel-mantix-mlaf057we51"
 22
 23/* Manufacturer specific Commands send via DSI */
 24#define MANTIX_CMD_OTP_STOP_RELOAD_MIPI 0x41
 25#define MANTIX_CMD_INT_CANCEL           0x4C
 26#define MANTIX_CMD_SPI_FINISH           0x90
 27
 28struct mantix {
 29	struct device *dev;
 30	struct drm_panel panel;
 31
 32	struct gpio_desc *reset_gpio;
 33	struct gpio_desc *tp_rstn_gpio;
 34
 35	struct regulator *avdd;
 36	struct regulator *avee;
 37	struct regulator *vddi;
 38
 39	const struct drm_display_mode *default_mode;
 40};
 41
 42static inline struct mantix *panel_to_mantix(struct drm_panel *panel)
 43{
 44	return container_of(panel, struct mantix, panel);
 45}
 46
 47#define dsi_generic_write_seq(dsi, seq...) do {				\
 48		static const u8 d[] = { seq };				\
 49		int ret;						\
 50		ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d));	\
 51		if (ret < 0)						\
 52			return ret;					\
 53	} while (0)
 54
 55static int mantix_init_sequence(struct mantix *ctx)
 56{
 57	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
 58	struct device *dev = ctx->dev;
 59
 60	/*
 61	 * Init sequence was supplied by the panel vendor.
 62	 */
 63	dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A);
 64
 65	dsi_generic_write_seq(dsi, MANTIX_CMD_INT_CANCEL, 0x03);
 66	dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x03);
 67	dsi_generic_write_seq(dsi, 0x80, 0xA9, 0x00);
 68
 69	dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x5A, 0x09);
 70	dsi_generic_write_seq(dsi, 0x80, 0x64, 0x00, 0x64, 0x00, 0x00);
 71	msleep(20);
 72
 73	dsi_generic_write_seq(dsi, MANTIX_CMD_SPI_FINISH, 0xA5);
 74	dsi_generic_write_seq(dsi, MANTIX_CMD_OTP_STOP_RELOAD_MIPI, 0x00, 0x2F);
 75	msleep(20);
 76
 77	dev_dbg(dev, "Panel init sequence done\n");
 78	return 0;
 79}
 80
 81static int mantix_enable(struct drm_panel *panel)
 82{
 83	struct mantix *ctx = panel_to_mantix(panel);
 84	struct device *dev = ctx->dev;
 85	struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
 86	int ret;
 87
 88	ret = mantix_init_sequence(ctx);
 89	if (ret < 0) {
 90		dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
 91		return ret;
 92	}
 93
 94	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
 95	if (ret < 0) {
 96		dev_err(dev, "Failed to exit sleep mode\n");
 97		return ret;
 98	}
 99	msleep(20);
100
101	ret = mipi_dsi_dcs_set_display_on(dsi);
102	if (ret)
103		return ret;
104	usleep_range(10000, 12000);
105
106	ret = mipi_dsi_turn_on_peripheral(dsi);
107	if (ret < 0) {
108		dev_err(dev, "Failed to turn on peripheral\n");
109		return ret;
110	}
111
112	return 0;
113}
114
115static int mantix_disable(struct drm_panel *panel)
116{
117	struct mantix *ctx = panel_to_mantix(panel);
118	struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
119	int ret;
120
121	ret = mipi_dsi_dcs_set_display_off(dsi);
122	if (ret < 0)
123		dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
124
125	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
126	if (ret < 0)
127		dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
128
129
130	return 0;
131}
132
133static int mantix_unprepare(struct drm_panel *panel)
134{
135	struct mantix *ctx = panel_to_mantix(panel);
136
137	gpiod_set_value_cansleep(ctx->tp_rstn_gpio, 1);
138	usleep_range(5000, 6000);
139	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
140
141	regulator_disable(ctx->avee);
142	regulator_disable(ctx->avdd);
143	/* T11 */
144	usleep_range(5000, 6000);
145	regulator_disable(ctx->vddi);
146	/* T14 */
147	msleep(50);
148
149	return 0;
150}
151
152static int mantix_prepare(struct drm_panel *panel)
153{
154	struct mantix *ctx = panel_to_mantix(panel);
155	int ret;
156
157	/* Focaltech FT8006P, section 7.3.1 and 7.3.4 */
158	dev_dbg(ctx->dev, "Resetting the panel\n");
159	ret = regulator_enable(ctx->vddi);
160	if (ret < 0) {
161		dev_err(ctx->dev, "Failed to enable vddi supply: %d\n", ret);
162		return ret;
163	}
164
165	/* T1 + T2 */
166	usleep_range(8000, 10000);
167
168	ret = regulator_enable(ctx->avdd);
169	if (ret < 0) {
170		dev_err(ctx->dev, "Failed to enable avdd supply: %d\n", ret);
171		return ret;
172	}
173
174	/* T2d */
175	usleep_range(3500, 4000);
176	ret = regulator_enable(ctx->avee);
177	if (ret < 0) {
178		dev_err(ctx->dev, "Failed to enable avee supply: %d\n", ret);
179		return ret;
180	}
181
182	/* T3 + T4 + time for voltage to become stable: */
183	usleep_range(6000, 7000);
184	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
185	gpiod_set_value_cansleep(ctx->tp_rstn_gpio, 0);
186
187	/* T6 */
188	msleep(50);
189
190	return 0;
191}
192
193static const struct drm_display_mode default_mode_mantix = {
194	.hdisplay    = 720,
195	.hsync_start = 720 + 45,
196	.hsync_end   = 720 + 45 + 14,
197	.htotal	     = 720 + 45 + 14 + 25,
198	.vdisplay    = 1440,
199	.vsync_start = 1440 + 130,
200	.vsync_end   = 1440 + 130 + 8,
201	.vtotal	     = 1440 + 130 + 8 + 106,
202	.clock	     = 85298,
203	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
204	.width_mm    = 65,
205	.height_mm   = 130,
206};
207
208static const struct drm_display_mode default_mode_ys = {
209	.hdisplay    = 720,
210	.hsync_start = 720 + 45,
211	.hsync_end   = 720 + 45 + 14,
212	.htotal	     = 720 + 45 + 14 + 25,
213	.vdisplay    = 1440,
214	.vsync_start = 1440 + 175,
215	.vsync_end   = 1440 + 175 + 8,
216	.vtotal	     = 1440 + 175 + 8 + 50,
217	.clock	     = 85298,
218	.flags	     = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
219	.width_mm    = 65,
220	.height_mm   = 130,
221};
222
223static int mantix_get_modes(struct drm_panel *panel,
224			    struct drm_connector *connector)
225{
226	struct mantix *ctx = panel_to_mantix(panel);
227	struct drm_display_mode *mode;
228
229	mode = drm_mode_duplicate(connector->dev, ctx->default_mode);
230	if (!mode) {
231		dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
232			ctx->default_mode->hdisplay, ctx->default_mode->vdisplay,
233			drm_mode_vrefresh(ctx->default_mode));
234		return -ENOMEM;
235	}
236
237	drm_mode_set_name(mode);
238
239	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
240	connector->display_info.width_mm = mode->width_mm;
241	connector->display_info.height_mm = mode->height_mm;
242	drm_mode_probed_add(connector, mode);
243
244	return 1;
245}
246
247static const struct drm_panel_funcs mantix_drm_funcs = {
248	.disable   = mantix_disable,
249	.unprepare = mantix_unprepare,
250	.prepare   = mantix_prepare,
251	.enable	   = mantix_enable,
252	.get_modes = mantix_get_modes,
253};
254
255static int mantix_probe(struct mipi_dsi_device *dsi)
256{
257	struct device *dev = &dsi->dev;
258	struct mantix *ctx;
259	int ret;
260
261	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
262	if (!ctx)
263		return -ENOMEM;
264	ctx->default_mode = of_device_get_match_data(dev);
265
266	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
267	if (IS_ERR(ctx->reset_gpio)) {
268		dev_err(dev, "cannot get reset gpio\n");
269		return PTR_ERR(ctx->reset_gpio);
270	}
271
272	ctx->tp_rstn_gpio = devm_gpiod_get(dev, "mantix,tp-rstn", GPIOD_OUT_HIGH);
273	if (IS_ERR(ctx->tp_rstn_gpio)) {
274		dev_err(dev, "cannot get tp-rstn gpio\n");
275		return PTR_ERR(ctx->tp_rstn_gpio);
276	}
277
278	mipi_dsi_set_drvdata(dsi, ctx);
279	ctx->dev = dev;
280
281	dsi->lanes = 4;
282	dsi->format = MIPI_DSI_FMT_RGB888;
283	dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
284		MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
285
286	ctx->avdd = devm_regulator_get(dev, "avdd");
287	if (IS_ERR(ctx->avdd))
288		return dev_err_probe(dev, PTR_ERR(ctx->avdd), "Failed to request avdd regulator\n");
289
290	ctx->avee = devm_regulator_get(dev, "avee");
291	if (IS_ERR(ctx->avee))
292		return dev_err_probe(dev, PTR_ERR(ctx->avee), "Failed to request avee regulator\n");
293
294	ctx->vddi = devm_regulator_get(dev, "vddi");
295	if (IS_ERR(ctx->vddi))
296		return dev_err_probe(dev, PTR_ERR(ctx->vddi), "Failed to request vddi regulator\n");
297
298	drm_panel_init(&ctx->panel, dev, &mantix_drm_funcs,
299		       DRM_MODE_CONNECTOR_DSI);
300
301	ret = drm_panel_of_backlight(&ctx->panel);
302	if (ret)
303		return ret;
304
305	drm_panel_add(&ctx->panel);
306
307	ret = mipi_dsi_attach(dsi);
308	if (ret < 0) {
309		dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
310		drm_panel_remove(&ctx->panel);
311		return ret;
312	}
313
314	dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
315		 ctx->default_mode->hdisplay, ctx->default_mode->vdisplay,
316		 drm_mode_vrefresh(ctx->default_mode),
317		 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
318
319	return 0;
320}
321
322static void mantix_shutdown(struct mipi_dsi_device *dsi)
323{
324	struct mantix *ctx = mipi_dsi_get_drvdata(dsi);
325
326	drm_panel_unprepare(&ctx->panel);
327	drm_panel_disable(&ctx->panel);
328}
329
330static int mantix_remove(struct mipi_dsi_device *dsi)
331{
332	struct mantix *ctx = mipi_dsi_get_drvdata(dsi);
333
334	mantix_shutdown(dsi);
335
336	mipi_dsi_detach(dsi);
337	drm_panel_remove(&ctx->panel);
338
339	return 0;
340}
341
342static const struct of_device_id mantix_of_match[] = {
343	{ .compatible = "mantix,mlaf057we51-x", .data = &default_mode_mantix },
344	{ .compatible = "ys,ys57pss36bh5gq", .data = &default_mode_ys },
345	{ /* sentinel */ }
346};
347MODULE_DEVICE_TABLE(of, mantix_of_match);
348
349static struct mipi_dsi_driver mantix_driver = {
350	.probe	= mantix_probe,
351	.remove = mantix_remove,
352	.shutdown = mantix_shutdown,
353	.driver = {
354		.name = DRV_NAME,
355		.of_match_table = mantix_of_match,
356	},
357};
358module_mipi_dsi_driver(mantix_driver);
359
360MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
361MODULE_DESCRIPTION("DRM driver for Mantix MLAF057WE51-X MIPI DSI panel");
362MODULE_LICENSE("GPL v2");