xref: /linux/drivers/gpu/drm/panel/panel-sharp-ls060t1sx01.c (revision 8c994eff8fcfe8ecb1f1dbebed25b4d7bb75be12)
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 
19 struct 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 	bool prepared;
28 };
29 
30 static inline struct sharp_ls060 *to_sharp_ls060(struct drm_panel *panel)
31 {
32 	return container_of(panel, struct sharp_ls060, panel);
33 }
34 
35 static void sharp_ls060_reset(struct sharp_ls060 *ctx)
36 {
37 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
38 	usleep_range(10000, 11000);
39 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
40 	usleep_range(10000, 11000);
41 	gpiod_set_value_cansleep(ctx->reset_gpio, 0);
42 	usleep_range(10000, 11000);
43 }
44 
45 static int sharp_ls060_on(struct sharp_ls060 *ctx)
46 {
47 	struct mipi_dsi_device *dsi = ctx->dsi;
48 	struct device *dev = &dsi->dev;
49 	int ret;
50 
51 	dsi->mode_flags |= MIPI_DSI_MODE_LPM;
52 
53 	mipi_dsi_dcs_write_seq(dsi, 0xbb, 0x13);
54 	mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_MEMORY_START);
55 
56 	ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
57 	if (ret < 0) {
58 		dev_err(dev, "Failed to exit sleep mode: %d\n", ret);
59 		return ret;
60 	}
61 	msleep(120);
62 
63 	ret = mipi_dsi_dcs_set_display_on(dsi);
64 	if (ret < 0) {
65 		dev_err(dev, "Failed to set display on: %d\n", ret);
66 		return ret;
67 	}
68 	msleep(50);
69 
70 	return 0;
71 }
72 
73 static int sharp_ls060_off(struct sharp_ls060 *ctx)
74 {
75 	struct mipi_dsi_device *dsi = ctx->dsi;
76 	struct device *dev = &dsi->dev;
77 	int ret;
78 
79 	dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
80 
81 	ret = mipi_dsi_dcs_set_display_off(dsi);
82 	if (ret < 0) {
83 		dev_err(dev, "Failed to set display off: %d\n", ret);
84 		return ret;
85 	}
86 	usleep_range(2000, 3000);
87 
88 	ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
89 	if (ret < 0) {
90 		dev_err(dev, "Failed to enter sleep mode: %d\n", ret);
91 		return ret;
92 	}
93 	msleep(121);
94 
95 	return 0;
96 }
97 
98 static int sharp_ls060_prepare(struct drm_panel *panel)
99 {
100 	struct sharp_ls060 *ctx = to_sharp_ls060(panel);
101 	struct device *dev = &ctx->dsi->dev;
102 	int ret;
103 
104 	if (ctx->prepared)
105 		return 0;
106 
107 	ret = regulator_enable(ctx->vddi_supply);
108 	if (ret < 0)
109 		return ret;
110 
111 	ret = regulator_enable(ctx->avdd_supply);
112 	if (ret < 0)
113 		goto err_avdd;
114 
115 	usleep_range(1000, 2000);
116 
117 	ret = regulator_enable(ctx->avee_supply);
118 	if (ret < 0)
119 		goto err_avee;
120 
121 	usleep_range(10000, 11000);
122 
123 	ret = regulator_enable(ctx->vddh_supply);
124 	if (ret < 0)
125 		goto err_vddh;
126 
127 	usleep_range(10000, 11000);
128 
129 	sharp_ls060_reset(ctx);
130 
131 	ret = sharp_ls060_on(ctx);
132 	if (ret < 0) {
133 		dev_err(dev, "Failed to initialize panel: %d\n", ret);
134 		goto err_on;
135 	}
136 
137 	ctx->prepared = true;
138 
139 	return 0;
140 
141 err_on:
142 	regulator_disable(ctx->vddh_supply);
143 
144 	usleep_range(10000, 11000);
145 
146 err_vddh:
147 	regulator_disable(ctx->avee_supply);
148 
149 err_avee:
150 	regulator_disable(ctx->avdd_supply);
151 
152 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
153 
154 err_avdd:
155 	regulator_disable(ctx->vddi_supply);
156 
157 	return ret;
158 }
159 
160 static int sharp_ls060_unprepare(struct drm_panel *panel)
161 {
162 	struct sharp_ls060 *ctx = to_sharp_ls060(panel);
163 	struct device *dev = &ctx->dsi->dev;
164 	int ret;
165 
166 	if (!ctx->prepared)
167 		return 0;
168 
169 	ret = sharp_ls060_off(ctx);
170 	if (ret < 0)
171 		dev_err(dev, "Failed to un-initialize panel: %d\n", ret);
172 
173 	regulator_disable(ctx->vddh_supply);
174 
175 	usleep_range(10000, 11000);
176 
177 	regulator_disable(ctx->avee_supply);
178 	regulator_disable(ctx->avdd_supply);
179 
180 	gpiod_set_value_cansleep(ctx->reset_gpio, 1);
181 
182 	regulator_disable(ctx->vddi_supply);
183 
184 	ctx->prepared = false;
185 	return 0;
186 }
187 
188 static const struct drm_display_mode sharp_ls060_mode = {
189 	.clock = (1080 + 96 + 16 + 64) * (1920 + 4 + 1 + 16) * 60 / 1000,
190 	.hdisplay = 1080,
191 	.hsync_start = 1080 + 96,
192 	.hsync_end = 1080 + 96 + 16,
193 	.htotal = 1080 + 96 + 16 + 64,
194 	.vdisplay = 1920,
195 	.vsync_start = 1920 + 4,
196 	.vsync_end = 1920 + 4 + 1,
197 	.vtotal = 1920 + 4 + 1 + 16,
198 	.width_mm = 75,
199 	.height_mm = 132,
200 };
201 
202 static int sharp_ls060_get_modes(struct drm_panel *panel,
203 				 struct drm_connector *connector)
204 {
205 	struct drm_display_mode *mode;
206 
207 	mode = drm_mode_duplicate(connector->dev, &sharp_ls060_mode);
208 	if (!mode)
209 		return -ENOMEM;
210 
211 	drm_mode_set_name(mode);
212 
213 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
214 	connector->display_info.width_mm = mode->width_mm;
215 	connector->display_info.height_mm = mode->height_mm;
216 	drm_mode_probed_add(connector, mode);
217 
218 	return 1;
219 }
220 
221 static const struct drm_panel_funcs sharp_ls060_panel_funcs = {
222 	.prepare = sharp_ls060_prepare,
223 	.unprepare = sharp_ls060_unprepare,
224 	.get_modes = sharp_ls060_get_modes,
225 };
226 
227 static int sharp_ls060_probe(struct mipi_dsi_device *dsi)
228 {
229 	struct device *dev = &dsi->dev;
230 	struct sharp_ls060 *ctx;
231 	int ret;
232 
233 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
234 	if (!ctx)
235 		return -ENOMEM;
236 
237 	ctx->vddi_supply = devm_regulator_get(dev, "vddi");
238 	if (IS_ERR(ctx->vddi_supply))
239 		return PTR_ERR(ctx->vddi_supply);
240 
241 	ctx->vddh_supply = devm_regulator_get(dev, "vddh");
242 	if (IS_ERR(ctx->vddh_supply))
243 		return PTR_ERR(ctx->vddh_supply);
244 
245 	ctx->avdd_supply = devm_regulator_get(dev, "avdd");
246 	if (IS_ERR(ctx->avdd_supply))
247 		return PTR_ERR(ctx->avdd_supply);
248 
249 	ctx->avee_supply = devm_regulator_get(dev, "avee");
250 	if (IS_ERR(ctx->avee_supply))
251 		return PTR_ERR(ctx->avee_supply);
252 
253 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
254 	if (IS_ERR(ctx->reset_gpio))
255 		return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio),
256 				     "Failed to get reset-gpios\n");
257 
258 	ctx->dsi = dsi;
259 	mipi_dsi_set_drvdata(dsi, ctx);
260 
261 	dsi->lanes = 4;
262 	dsi->format = MIPI_DSI_FMT_RGB888;
263 	dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
264 			  MIPI_DSI_MODE_NO_EOT_PACKET |
265 			  MIPI_DSI_CLOCK_NON_CONTINUOUS;
266 
267 	drm_panel_init(&ctx->panel, dev, &sharp_ls060_panel_funcs,
268 		       DRM_MODE_CONNECTOR_DSI);
269 
270 	ret = drm_panel_of_backlight(&ctx->panel);
271 	if (ret)
272 		return dev_err_probe(dev, ret, "Failed to get backlight\n");
273 
274 	drm_panel_add(&ctx->panel);
275 
276 	ret = mipi_dsi_attach(dsi);
277 	if (ret < 0) {
278 		dev_err(dev, "Failed to attach to DSI host: %d\n", ret);
279 		drm_panel_remove(&ctx->panel);
280 		return ret;
281 	}
282 
283 	return 0;
284 }
285 
286 static void sharp_ls060_remove(struct mipi_dsi_device *dsi)
287 {
288 	struct sharp_ls060 *ctx = mipi_dsi_get_drvdata(dsi);
289 	int ret;
290 
291 	ret = mipi_dsi_detach(dsi);
292 	if (ret < 0)
293 		dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
294 
295 	drm_panel_remove(&ctx->panel);
296 }
297 
298 static const struct of_device_id sharp_ls060t1sx01_of_match[] = {
299 	{ .compatible = "sharp,ls060t1sx01" },
300 	{ /* sentinel */ }
301 };
302 MODULE_DEVICE_TABLE(of, sharp_ls060t1sx01_of_match);
303 
304 static struct mipi_dsi_driver sharp_ls060_driver = {
305 	.probe = sharp_ls060_probe,
306 	.remove = sharp_ls060_remove,
307 	.driver = {
308 		.name = "panel-sharp-ls060t1sx01",
309 		.of_match_table = sharp_ls060t1sx01_of_match,
310 	},
311 };
312 module_mipi_dsi_driver(sharp_ls060_driver);
313 
314 MODULE_AUTHOR("Dmitry Baryshkov <dmitry.baryshkov@linaro.org>");
315 MODULE_DESCRIPTION("DRM driver for Sharp LS060T1SX01 1080p video mode dsi panel");
316 MODULE_LICENSE("GPL v2");
317