File Index
Files and directories
Sign in
FILE

panel-visionox-g2647fb105.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-visionox-g2647fb105.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
  4 *   Copyright (c) 2013, The Linux Foundation. All rights reserved.
  5 *   Copyright (c) 2025, Alexander Baransky <sanyapilot496@gmail.com>
  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.h>
 13#include <linux/regulator/consumer.h>
 14
 15#include <drm/drm_mipi_dsi.h>
 16#include <drm/drm_modes.h>
 17#include <drm/drm_panel.h>
 18
 19struct visionox_g2647fb105 {
 20	struct drm_panel panel;
 21	struct mipi_dsi_device *dsi;
 22	struct gpio_desc *reset_gpio;
 23	struct regulator_bulk_data *supplies;
 24};
 25
 26static const struct regulator_bulk_data visionox_g2647fb105_supplies[] = {
 27	{ .supply = "vdd3p3" },
 28	{ .supply = "vddio" },
 29	{ .supply = "vsn" },
 30	{ .supply = "vsp" },
 31};
 32
 33static inline
 34struct visionox_g2647fb105 *to_visionox_g2647fb105(struct drm_panel *panel)
 35{
 36	return container_of(panel, struct visionox_g2647fb105, panel);
 37}
 38
 39static void visionox_g2647fb105_reset(struct visionox_g2647fb105 *ctx)
 40{
 41	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 42	usleep_range(1000, 2000);
 43	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 44	usleep_range(10000, 11000);
 45}
 46
 47static int visionox_g2647fb105_on(struct visionox_g2647fb105 *ctx)
 48{
 49	struct mipi_dsi_device *dsi = ctx->dsi;
 50	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 51
 52	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x70, 0x04);
 53	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
 54	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x4d, 0x32);
 55	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x40);
 56	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbe, 0x17);
 57	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbf, 0xbb);
 58	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc0, 0xdd);
 59	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc1, 0xff);
 60	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0xd0);
 61	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x03, 0x24);
 62	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x03);
 63	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
 64	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xc2, 0x08);
 65	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xfe, 0x00);
 66
 67	mipi_dsi_dcs_set_tear_on_multi(&dsi_ctx, MIPI_DSI_DCS_TEAR_MODE_VBLANK);
 68	mipi_dsi_dcs_set_display_brightness_multi(&dsi_ctx, 0x0000);
 69	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
 70	mipi_dsi_msleep(&dsi_ctx, 100);
 71
 72	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
 73
 74	return dsi_ctx.accum_err;
 75}
 76
 77static int visionox_g2647fb105_off(struct visionox_g2647fb105 *ctx)
 78{
 79	struct mipi_dsi_device *dsi = ctx->dsi;
 80	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 81
 82	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
 83	mipi_dsi_msleep(&dsi_ctx, 50);
 84
 85	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
 86	mipi_dsi_msleep(&dsi_ctx, 20);
 87
 88	return dsi_ctx.accum_err;
 89}
 90
 91static int visionox_g2647fb105_prepare(struct drm_panel *panel)
 92{
 93	struct visionox_g2647fb105 *ctx = to_visionox_g2647fb105(panel);
 94	struct device *dev = &ctx->dsi->dev;
 95	int ret;
 96
 97	ret = regulator_bulk_enable(ARRAY_SIZE(visionox_g2647fb105_supplies), ctx->supplies);
 98	if (ret < 0) {
 99		dev_err(dev, "Failed to enable regulators: %d\n", ret);
100		return ret;
101	}
102
103	visionox_g2647fb105_reset(ctx);
104
105	ret = visionox_g2647fb105_on(ctx);
106	if (ret < 0) {
107		dev_err(dev, "Failed to initialize panel: %d\n", ret);
108		return ret;
109	}
110
111	return 0;
112}
113
114static int visionox_g2647fb105_unprepare(struct drm_panel *panel)
115{
116	struct visionox_g2647fb105 *ctx = to_visionox_g2647fb105(panel);
117	struct device *dev = &ctx->dsi->dev;
118	int ret;
119
120	ret = visionox_g2647fb105_off(ctx);
121	if (ret < 0)
122		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
123
124	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
125	regulator_bulk_disable(ARRAY_SIZE(visionox_g2647fb105_supplies), ctx->supplies);
126
127	return 0;
128}
129
130static const struct drm_display_mode visionox_g2647fb105_mode = {
131	.clock = (1080 + 28 + 4 + 36) * (2340 + 8 + 4 + 4) * 60 / 1000,
132	.hdisplay = 1080,
133	.hsync_start = 1080 + 28,
134	.hsync_end = 1080 + 28 + 4,
135	.htotal = 1080 + 28 + 4 + 36,
136	.vdisplay = 2340,
137	.vsync_start = 2340 + 8,
138	.vsync_end = 2340 + 8 + 4,
139	.vtotal = 2340 + 8 + 4 + 4,
140	.width_mm = 69,
141	.height_mm = 149,
142};
143
144static int visionox_g2647fb105_get_modes(struct drm_panel *panel,
145					struct drm_connector *connector)
146{
147	struct drm_display_mode *mode;
148
149	mode = drm_mode_duplicate(connector->dev, &visionox_g2647fb105_mode);
150	if (!mode)
151		return -ENOMEM;
152
153	drm_mode_set_name(mode);
154
155	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
156	connector->display_info.width_mm = mode->width_mm;
157	connector->display_info.height_mm = mode->height_mm;
158	drm_mode_probed_add(connector, mode);
159
160	return 1;
161}
162
163static const struct drm_panel_funcs visionox_g2647fb105_panel_funcs = {
164	.prepare = visionox_g2647fb105_prepare,
165	.unprepare = visionox_g2647fb105_unprepare,
166	.get_modes = visionox_g2647fb105_get_modes,
167};
168
169static int visionox_g2647fb105_bl_update_status(struct backlight_device *bl)
170{
171	struct mipi_dsi_device *dsi = bl_get_data(bl);
172	u16 brightness = backlight_get_brightness(bl);
173	int ret;
174
175	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
176
177	ret = mipi_dsi_dcs_set_display_brightness_large(dsi, brightness);
178	if (ret < 0)
179		return ret;
180
181	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
182
183	return 0;
184}
185
186static const struct backlight_ops visionox_g2647fb105_bl_ops = {
187	.update_status = visionox_g2647fb105_bl_update_status,
188};
189
190static struct backlight_device *
191visionox_g2647fb105_create_backlight(struct mipi_dsi_device *dsi)
192{
193	struct device *dev = &dsi->dev;
194	const struct backlight_properties props = {
195		.type = BACKLIGHT_RAW,
196		.brightness = 1023,
197		.max_brightness = 2047,
198	};
199
200	return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
201					      &visionox_g2647fb105_bl_ops, &props);
202}
203
204static int visionox_g2647fb105_probe(struct mipi_dsi_device *dsi)
205{
206	struct device *dev = &dsi->dev;
207	struct visionox_g2647fb105 *ctx;
208	int ret;
209
210	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
211	if (!ctx)
212		return -ENOMEM;
213
214	ret = devm_regulator_bulk_get_const(dev,
215					    ARRAY_SIZE(visionox_g2647fb105_supplies),
216					    visionox_g2647fb105_supplies,
217					    &ctx->supplies);
218	if (ret < 0)
219		return dev_err_probe(dev, ret, "Failed to get regulators\n");
220
221	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
222	if (IS_ERR(ctx->reset_gpio))
223		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
224				     "Failed to get reset-gpios\n");
225
226	ctx->dsi = dsi;
227	mipi_dsi_set_drvdata(dsi, ctx);
228
229	dsi->lanes = 4;
230	dsi->format = MIPI_DSI_FMT_RGB888;
231	dsi->mode_flags = MIPI_DSI_MODE_VIDEO_BURST |
232			  MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM;
233
234	ctx->panel.prepare_prev_first = true;
235
236	drm_panel_init(&ctx->panel, dev, &visionox_g2647fb105_panel_funcs,
237		       DRM_MODE_CONNECTOR_DSI);
238	ctx->panel.prepare_prev_first = true;
239
240	ctx->panel.backlight = visionox_g2647fb105_create_backlight(dsi);
241	if (IS_ERR(ctx->panel.backlight))
242		return dev_err_probe(dev, PTR_ERR(ctx->panel.backlight),
243				     "Failed to create backlight\n");
244
245	drm_panel_add(&ctx->panel);
246
247	ret = devm_mipi_dsi_attach(dev, dsi);
248	if (ret < 0) {
249		drm_panel_remove(&ctx->panel);
250		return dev_err_probe(dev, ret, "Failed to attach to DSI host\n");
251	}
252
253	return 0;
254}
255
256static void visionox_g2647fb105_remove(struct mipi_dsi_device *dsi)
257{
258	struct visionox_g2647fb105 *ctx = mipi_dsi_get_drvdata(dsi);
259	drm_panel_remove(&ctx->panel);
260}
261
262static const struct of_device_id visionox_g2647fb105_of_match[] = {
263	{ .compatible = "visionox,g2647fb105" },
264	{ /* sentinel */ }
265};
266MODULE_DEVICE_TABLE(of, visionox_g2647fb105_of_match);
267
268static struct mipi_dsi_driver visionox_g2647fb105_driver = {
269	.probe = visionox_g2647fb105_probe,
270	.remove = visionox_g2647fb105_remove,
271	.driver = {
272		.name = "panel-visionox-g2647fb105",
273		.of_match_table = visionox_g2647fb105_of_match,
274	},
275};
276module_mipi_dsi_driver(visionox_g2647fb105_driver);
277
278MODULE_AUTHOR("Alexander Baransky <sanyapilot496@gmail.com>");
279MODULE_DESCRIPTION("DRM driver for Visionox G2647FB105 AMOLED DSI panel");
280MODULE_LICENSE("GPL");
~/ Read-only file preview.