File Index
Files and directories
Sign in
FILE

panel-sharp-ls060t1sx01.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2/* Copyright (c) 2021 Linaro Ltd.
  3 * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree:
  4 *   Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
  5 */
  6
  7#include <linux/delay.h>
  8#include <linux/gpio/consumer.h>
  9#include <linux/module.h>
 10#include <linux/of.h>
 11#include <linux/regulator/consumer.h>
 12
 13#include <video/mipi_display.h>
 14
 15#include <drm/drm_mipi_dsi.h>
 16#include <drm/drm_modes.h>
 17#include <drm/drm_panel.h>
 18
 19struct sharp_ls060 {
 20	struct drm_panel panel;
 21	struct mipi_dsi_device *dsi;
 22	struct regulator *vddi_supply;
 23	struct regulator *vddh_supply;
 24	struct regulator *avdd_supply;
 25	struct regulator *avee_supply;
 26	struct gpio_desc *reset_gpio;
 27};
 28
 29static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel)
 30{
 31	return container_of(panel, struct sharp_ls060, panel);
 32}
 33
 34static void sharp_ls060_reset(struct sharp_ls060 *ctx)
 35{
 36	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 37	usleep_range(10000, 11000);
 38	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
 39	usleep_range(10000, 11000);
 40	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
 41	usleep_range(10000, 11000);
 42}
 43
 44static int sharp_ls060_on(struct sharp_ls060 *ctx)
 45{
 46	struct mipi_dsi_device *dsi = ctx->dsi;
 47	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 48
 49	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
 50
 51	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xbb, 0x13);
 52	mipi_dsi_dcs_write_seq_multi(&dsi_ctx, MIPI_DCS_WRITE_MEMORY_START);
 53
 54	mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx);
 55	mipi_dsi_msleep(&dsi_ctx, 120);
 56
 57	mipi_dsi_dcs_set_display_on_multi(&dsi_ctx);
 58	mipi_dsi_msleep(&dsi_ctx, 50);
 59
 60	return dsi_ctx.accum_err;
 61}
 62
 63static void sharp_ls060_off(struct sharp_ls060 *ctx)
 64{
 65	struct mipi_dsi_device *dsi = ctx->dsi;
 66	struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi };
 67
 68	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
 69
 70	mipi_dsi_dcs_set_display_off_multi(&dsi_ctx);
 71	mipi_dsi_usleep_range(&dsi_ctx, 2000, 3000);
 72
 73	mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx);
 74	mipi_dsi_msleep(&dsi_ctx, 121);
 75}
 76
 77static int sharp_ls060_prepare(struct drm_panel *panel)
 78{
 79	struct sharp_ls060 *ctx = to_sharp_ls060(panel);
 80	int ret;
 81
 82	ret = regulator_enable(ctx->vddi_supply);
 83	if (ret < 0)
 84		return ret;
 85
 86	ret = regulator_enable(ctx->avdd_supply);
 87	if (ret < 0)
 88		goto err_avdd;
 89
 90	usleep_range(1000, 2000);
 91
 92	ret = regulator_enable(ctx->avee_supply);
 93	if (ret < 0)
 94		goto err_avee;
 95
 96	usleep_range(10000, 11000);
 97
 98	ret = regulator_enable(ctx->vddh_supply);
 99	if (ret < 0)
100		goto err_vddh;
101
102	usleep_range(10000, 11000);
103
104	sharp_ls060_reset(ctx);
105
106	ret = sharp_ls060_on(ctx);
107	if (ret < 0)
108		goto err_on;
109
110	return 0;
111
112err_on:
113	regulator_disable(ctx->vddh_supply);
114
115	usleep_range(10000, 11000);
116
117err_vddh:
118	regulator_disable(ctx->avee_supply);
119
120err_avee:
121	regulator_disable(ctx->avdd_supply);
122
123	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
124
125err_avdd:
126	regulator_disable(ctx->vddi_supply);
127
128	return ret;
129}
130
131static int sharp_ls060_unprepare(struct drm_panel *panel)
132{
133	struct sharp_ls060 *ctx = to_sharp_ls060(panel);
134
135	sharp_ls060_off(ctx);
136
137	regulator_disable(ctx->vddh_supply);
138
139	usleep_range(10000, 11000);
140
141	regulator_disable(ctx->avee_supply);
142	regulator_disable(ctx->avdd_supply);
143
144	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
145
146	regulator_disable(ctx->vddi_supply);
147
148	return 0;
149}
150
151static const struct drm_display_mode sharp_ls060_mode = {
152	.clock = (1080 + 96 + 16 + 64) * (1920 + 4 + 1 + 16) * 60 / 1000,
153	.hdisplay = 1080,
154	.hsync_start = 1080 + 96,
155	.hsync_end = 1080 + 96 + 16,
156	.htotal = 1080 + 96 + 16 + 64,
157	.vdisplay = 1920,
158	.vsync_start = 1920 + 4,
159	.vsync_end = 1920 + 4 + 1,
160	.vtotal = 1920 + 4 + 1 + 16,
161	.width_mm = 75,
162	.height_mm = 132,
163};
164
165static int sharp_ls060_get_modes(struct drm_panel *panel,
166				 struct drm_connector *connector)
167{
168	struct drm_display_mode *mode;
169
170	mode = drm_mode_duplicate(connector->dev, &sharp_ls060_mode);
171	if (!mode)
172		return -ENOMEM;
173
174	drm_mode_set_name(mode);
175
176	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
177	connector->display_info.width_mm = mode->width_mm;
178	connector->display_info.height_mm = mode->height_mm;
179	drm_mode_probed_add(connector, mode);
180
181	return 1;
182}
183
184static const struct drm_panel_funcs sharp_ls060_panel_funcs = {
185	.prepare = sharp_ls060_prepare,
186	.unprepare = sharp_ls060_unprepare,
187	.get_modes = sharp_ls060_get_modes,
188};
189
190static int sharp_ls060_probe(struct mipi_dsi_device *dsi)
191{
192	struct device *dev = &dsi->dev;
193	struct sharp_ls060 *ctx;
194	int ret;
195
196	ctx = devm_drm_panel_alloc(dev, struct sharp_ls060, panel,
197				   &sharp_ls060_panel_funcs,
198				   DRM_MODE_CONNECTOR_DSI);
199	if (IS_ERR(ctx))
200		return PTR_ERR(ctx);
201
202	ctx->vddi_supply = devm_regulator_get(dev, "vddi");
203	if (IS_ERR(ctx->vddi_supply))
204		return PTR_ERR(ctx->vddi_supply);
205
206	ctx->vddh_supply = devm_regulator_get(dev, "vddh");
207	if (IS_ERR(ctx->vddh_supply))
208		return PTR_ERR(ctx->vddh_supply);
209
210	ctx->avdd_supply = devm_regulator_get(dev, "avdd");
211	if (IS_ERR(ctx->avdd_supply))
212		return PTR_ERR(ctx->avdd_supply);
213
214	ctx->avee_supply = devm_regulator_get(dev, "avee");
215	if (IS_ERR(ctx->avee_supply))
216		return PTR_ERR(ctx->avee_supply);
217
218	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
219	if (IS_ERR(ctx->reset_gpio))
220		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
221				     "Failed to get reset-gpios\n");
222
223	ctx->dsi = dsi;
224	mipi_dsi_set_drvdata(dsi, ctx);
225
226	dsi->lanes = 4;
227	dsi->format = MIPI_DSI_FMT_RGB888;
228	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
229			  MIPI_DSI_MODE_NO_EOT_PACKET |
230			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
231
232	ret = drm_panel_of_backlight(&ctx->panel);
233	if (ret)
234		return dev_err_probe(dev, ret, "Failed to get backlight\n");
235
236	drm_panel_add(&ctx->panel);
237
238	ret = mipi_dsi_attach(dsi);
239	if (ret < 0) {
240		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
241		drm_panel_remove(&ctx->panel);
242		return ret;
243	}
244
245	return 0;
246}
247
248static void sharp_ls060_remove(struct mipi_dsi_device *dsi)
249{
250	struct sharp_ls060 *ctx = mipi_dsi_get_drvdata(dsi);
251	int ret;
252
253	ret = mipi_dsi_detach(dsi);
254	if (ret < 0)
255		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
256
257	drm_panel_remove(&ctx->panel);
258}
259
260static const struct of_device_id sharp_ls060t1sx01_of_match[] = {
261	{ .compatible = "sharp,ls060t1sx01" },
262	{ /* sentinel */ }
263};
264MODULE_DEVICE_TABLE(of, sharp_ls060t1sx01_of_match);
265
266static struct mipi_dsi_driver sharp_ls060_driver = {
267	.probe = sharp_ls060_probe,
268	.remove = sharp_ls060_remove,
269	.driver = {
270		.name = "panel-sharp-ls060t1sx01",
271		.of_match_table = sharp_ls060t1sx01_of_match,
272	},
273};
274module_mipi_dsi_driver(sharp_ls060_driver);
275
276MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
277MODULE_DESCRIPTION("DRM driver for Sharp LS060T1SX01 1080p video mode dsi panel");
278MODULE_LICENSE("GPL v2");
~/ Read-only file preview.