File Index
Files and directories
Sign in
FILE

panel-ebbg-ft8719.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-ebbg-ft8719.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Copyright (c) 2022 Joel Selvaraj <jo@jsfamily.in>
  4 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
  5 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
  6 */
  7
  8#include <linux/delay.h>
  9#include <linux/gpio/consumer.h>
 10#include <linux/regulator/consumer.h>
 11#include <linux/module.h>
 12#include <linux/of.h>
 13
 14#include <video/mipi_display.h>
 15
 16#include <drm/drm_mipi_dsi.h>
 17#include <drm/drm_modes.h>
 18#include <drm/drm_panel.h>
 19
 20static const char * const regulator_names[] = {
 21	"vddio",
 22	"vddpos",
 23	"vddneg",
 24};
 25
 26static const unsigned long regulator_enable_loads[] = {
 27	62000,
 28	100000,
 29	100000
 30};
 31
 32struct ebbg_ft8719 {
 33	struct drm_panel panel;
 34	struct mipi_dsi_device *dsi;
 35
 36	struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
 37
 38	struct gpio_desc *reset_gpio;
 39};
 40
 41static inline
 42struct ebbg_ft8719 *to_ebbg_ft8719(struct drm_panel *panel)
 43{
 44	return container_of(panel, struct ebbg_ft8719, panel);
 45}
 46
 47static void ebbg_ft8719_reset(struct ebbg_ft8719 *ctx)
 48{
 49	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 50	usleep_range(4000, 5000);
 51	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 52	usleep_range(1000, 2000);
 53	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 54	usleep_range(15000, 16000);
 55}
 56
 57static int ebbg_ft8719_on(struct ebbg_ft8719 *ctx)
 58{
 59	struct mipi_dsi_device *dsi = ctx->dsi;
 60	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 61
 62	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 63
 64	mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x00ff);
 65	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24);
 66	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_POWER_SAVE, 0x00);
 67
 68	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
 69	mipi_dsi_msleep(&dsi_ctx, 90);
 70	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
 71
 72	return dsi_ctx.accum_err;
 73}
 74
 75static int ebbg_ft8719_off(struct ebbg_ft8719 *ctx)
 76{
 77	struct mipi_dsi_device *dsi = ctx->dsi;
 78	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 79
 80	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 81
 82	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
 83	mipi_dsi_usleep_range(&dsi_ctx, 10000, 11000);
 84	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
 85	mipi_dsi_msleep(&dsi_ctx, 90);
 86
 87	return dsi_ctx.accum_err;
 88}
 89
 90static int ebbg_ft8719_prepare(struct drm_panel *panel)
 91{
 92	struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
 93	int ret;
 94
 95	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
 96	if (ret < 0)
 97		return ret;
 98
 99	ebbg_ft8719_reset(ctx);
100
101	ret = ebbg_ft8719_on(ctx);
102	if (ret < 0) {
103		gpiod_set_value_cansleep(ctx->reset_gpio, 1);
104		return ret;
105	}
106
107	return 0;
108}
109
110static int ebbg_ft8719_unprepare(struct drm_panel *panel)
111{
112	struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel);
113
114	ebbg_ft8719_off(ctx);
115	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
116	regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
117
118	return 0;
119}
120
121static const struct drm_display_mode ebbg_ft8719_mode = {
122	.clock = (1080 + 28 + 4 + 16) * (2246 + 120 + 4 + 12) * 60 / 1000,
123	.hdisplay = 1080,
124	.hsync_start = 1080 + 28,
125	.hsync_end = 1080 + 28 + 4,
126	.htotal = 1080 + 28 + 4 + 16,
127	.vdisplay = 2246,
128	.vsync_start = 2246 + 120,
129	.vsync_end = 2246 + 120 + 4,
130	.vtotal = 2246 + 120 + 4 + 12,
131	.width_mm = 68,
132	.height_mm = 141,
133};
134
135static int ebbg_ft8719_get_modes(struct drm_panel *panel,
136				     struct drm_connector *connector)
137{
138	struct drm_display_mode *mode;
139
140	mode = drm_mode_duplicate(connector->dev, &ebbg_ft8719_mode);
141	if (!mode)
142		return -ENOMEM;
143
144	drm_mode_set_name(mode);
145
146	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
147	connector->display_info.width_mm = mode->width_mm;
148	connector->display_info.height_mm = mode->height_mm;
149	drm_mode_probed_add(connector, mode);
150
151	return 1;
152}
153
154static const struct drm_panel_funcs ebbg_ft8719_panel_funcs = {
155	.prepare = ebbg_ft8719_prepare,
156	.unprepare = ebbg_ft8719_unprepare,
157	.get_modes = ebbg_ft8719_get_modes,
158};
159
160static int ebbg_ft8719_probe(struct mipi_dsi_device *dsi)
161{
162	struct device *dev = &dsi->dev;
163	struct ebbg_ft8719 *ctx;
164	int i, ret;
165
166	ctx = devm_drm_panel_alloc(dev, struct ebbg_ft8719, panel,
167				   &ebbg_ft8719_panel_funcs,
168				   DRM_MODE_CONNECTOR_DSI);
169	if (IS_ERR(ctx))
170		return PTR_ERR(ctx);
171
172	for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++)
173		ctx->supplies[i].supply = regulator_names[i];
174
175	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
176				      ctx->supplies);
177	if (ret < 0)
178		return dev_err_probe(dev, ret, "Failed to get regulators\n");
179
180	for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) {
181		ret = regulator_set_load(ctx->supplies[i].consumer,
182						regulator_enable_loads[i]);
183		if (ret)
184			return dev_err_probe(dev, ret,
185						 "Failed to set regulator load\n");
186	}
187
188	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
189	if (IS_ERR(ctx->reset_gpio))
190		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
191				     "Failed to get reset-gpios\n");
192
193	ctx->dsi = dsi;
194	mipi_dsi_set_drvdata(dsi, ctx);
195
196	dsi->lanes = 4;
197	dsi->format = MIPI_DSI_FMT_RGB888;
198	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
199			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
200
201	ret = drm_panel_of_backlight(&ctx->panel);
202	if (ret)
203		return dev_err_probe(dev, ret, "Failed to get backlight\n");
204
205	drm_panel_add(&ctx->panel);
206
207	ret = mipi_dsi_attach(dsi);
208	if (ret < 0) {
209		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
210		drm_panel_remove(&ctx->panel);
211		return ret;
212	}
213
214	return 0;
215}
216
217static void ebbg_ft8719_remove(struct mipi_dsi_device *dsi)
218{
219	struct ebbg_ft8719 *ctx = mipi_dsi_get_drvdata(dsi);
220	int ret;
221
222	ret = mipi_dsi_detach(dsi);
223	if (ret < 0)
224		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
225
226	drm_panel_remove(&ctx->panel);
227}
228
229static const struct of_device_id ebbg_ft8719_of_match[] = {
230	{ .compatible = "ebbg,ft8719" },
231	{ /* sentinel */ }
232};
233MODULE_DEVICE_TABLE(of, ebbg_ft8719_of_match);
234
235static struct mipi_dsi_driver ebbg_ft8719_driver = {
236	.probe = ebbg_ft8719_probe,
237	.remove = ebbg_ft8719_remove,
238	.driver = {
239		.name = "panel-ebbg-ft8719",
240		.of_match_table = ebbg_ft8719_of_match,
241	},
242};
243module_mipi_dsi_driver(ebbg_ft8719_driver);
244
245MODULE_AUTHOR("Joel Selvaraj <jo@jsfamily.in>");
246MODULE_DESCRIPTION("DRM driver for EBBG FT8719 video dsi panel");
247MODULE_LICENSE("GPL v2");
~/ Read-only file preview.