treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / gpu / drm / panel / panel-rocktech-jh057n00900.c
blob38ff742bc1209f8ff41ec3ee0cf2cff9a672306f
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Rockteck jh057n00900 5.5" MIPI-DSI panel driver
5 * Copyright (C) Purism SPC 2019
6 */
8 #include <linux/debugfs.h>
9 #include <linux/delay.h>
10 #include <linux/gpio/consumer.h>
11 #include <linux/media-bus-format.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/regulator/consumer.h>
16 #include <video/display_timing.h>
17 #include <video/mipi_display.h>
19 #include <drm/drm_mipi_dsi.h>
20 #include <drm/drm_modes.h>
21 #include <drm/drm_panel.h>
22 #include <drm/drm_print.h>
24 #define DRV_NAME "panel-rocktech-jh057n00900"
26 /* Manufacturer specific Commands send via DSI */
27 #define ST7703_CMD_ALL_PIXEL_OFF 0x22
28 #define ST7703_CMD_ALL_PIXEL_ON 0x23
29 #define ST7703_CMD_SETDISP 0xB2
30 #define ST7703_CMD_SETRGBIF 0xB3
31 #define ST7703_CMD_SETCYC 0xB4
32 #define ST7703_CMD_SETBGP 0xB5
33 #define ST7703_CMD_SETVCOM 0xB6
34 #define ST7703_CMD_SETOTP 0xB7
35 #define ST7703_CMD_SETPOWER_EXT 0xB8
36 #define ST7703_CMD_SETEXTC 0xB9
37 #define ST7703_CMD_SETMIPI 0xBA
38 #define ST7703_CMD_SETVDC 0xBC
39 #define ST7703_CMD_UNKNOWN0 0xBF
40 #define ST7703_CMD_SETSCR 0xC0
41 #define ST7703_CMD_SETPOWER 0xC1
42 #define ST7703_CMD_SETPANEL 0xCC
43 #define ST7703_CMD_SETGAMMA 0xE0
44 #define ST7703_CMD_SETEQ 0xE3
45 #define ST7703_CMD_SETGIP1 0xE9
46 #define ST7703_CMD_SETGIP2 0xEA
48 struct jh057n {
49 struct device *dev;
50 struct drm_panel panel;
51 struct gpio_desc *reset_gpio;
52 struct regulator *vcc;
53 struct regulator *iovcc;
54 bool prepared;
56 struct dentry *debugfs;
59 static inline struct jh057n *panel_to_jh057n(struct drm_panel *panel)
61 return container_of(panel, struct jh057n, panel);
64 #define dsi_generic_write_seq(dsi, seq...) do { \
65 static const u8 d[] = { seq }; \
66 int ret; \
67 ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
68 if (ret < 0) \
69 return ret; \
70 } while (0)
72 static int jh057n_init_sequence(struct jh057n *ctx)
74 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
75 struct device *dev = ctx->dev;
76 int ret;
79 * Init sequence was supplied by the panel vendor. Most of the commands
80 * resemble the ST7703 but the number of parameters often don't match
81 * so it's likely a clone.
83 dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
84 0xF1, 0x12, 0x83);
85 dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
86 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
87 0x00, 0x00);
88 dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
89 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
90 0x00);
91 dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
92 dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
93 dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
94 dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
95 dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
96 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
97 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
98 dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
99 msleep(20);
101 dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
102 dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN0, 0x02, 0x11, 0x00);
103 dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
104 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
105 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
106 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
107 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
108 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
109 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
110 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
112 dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
113 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
114 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
115 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
116 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
117 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
119 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
120 0xA5, 0x00, 0x00, 0x00, 0x00);
121 dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
122 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
123 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
124 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
125 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
126 0x11, 0x18);
127 msleep(20);
129 ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
130 if (ret < 0) {
131 DRM_DEV_ERROR(dev, "Failed to exit sleep mode: %d\n", ret);
132 return ret;
134 /* Panel is operational 120 msec after reset */
135 msleep(60);
136 ret = mipi_dsi_dcs_set_display_on(dsi);
137 if (ret)
138 return ret;
140 DRM_DEV_DEBUG_DRIVER(dev, "Panel init sequence done\n");
141 return 0;
144 static int jh057n_enable(struct drm_panel *panel)
146 struct jh057n *ctx = panel_to_jh057n(panel);
147 int ret;
149 ret = jh057n_init_sequence(ctx);
150 if (ret < 0) {
151 DRM_DEV_ERROR(ctx->dev, "Panel init sequence failed: %d\n",
152 ret);
153 return ret;
156 return 0;
159 static int jh057n_disable(struct drm_panel *panel)
161 struct jh057n *ctx = panel_to_jh057n(panel);
162 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
164 return mipi_dsi_dcs_set_display_off(dsi);
167 static int jh057n_unprepare(struct drm_panel *panel)
169 struct jh057n *ctx = panel_to_jh057n(panel);
171 if (!ctx->prepared)
172 return 0;
174 regulator_disable(ctx->iovcc);
175 regulator_disable(ctx->vcc);
176 ctx->prepared = false;
178 return 0;
181 static int jh057n_prepare(struct drm_panel *panel)
183 struct jh057n *ctx = panel_to_jh057n(panel);
184 int ret;
186 if (ctx->prepared)
187 return 0;
189 DRM_DEV_DEBUG_DRIVER(ctx->dev, "Resetting the panel\n");
190 ret = regulator_enable(ctx->vcc);
191 if (ret < 0) {
192 DRM_DEV_ERROR(ctx->dev,
193 "Failed to enable vcc supply: %d\n", ret);
194 return ret;
196 ret = regulator_enable(ctx->iovcc);
197 if (ret < 0) {
198 DRM_DEV_ERROR(ctx->dev,
199 "Failed to enable iovcc supply: %d\n", ret);
200 goto disable_vcc;
203 gpiod_set_value_cansleep(ctx->reset_gpio, 1);
204 usleep_range(20, 40);
205 gpiod_set_value_cansleep(ctx->reset_gpio, 0);
206 msleep(20);
208 ctx->prepared = true;
210 return 0;
212 disable_vcc:
213 regulator_disable(ctx->vcc);
214 return ret;
217 static const struct drm_display_mode default_mode = {
218 .hdisplay = 720,
219 .hsync_start = 720 + 90,
220 .hsync_end = 720 + 90 + 20,
221 .htotal = 720 + 90 + 20 + 20,
222 .vdisplay = 1440,
223 .vsync_start = 1440 + 20,
224 .vsync_end = 1440 + 20 + 4,
225 .vtotal = 1440 + 20 + 4 + 12,
226 .vrefresh = 60,
227 .clock = 75276,
228 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
229 .width_mm = 65,
230 .height_mm = 130,
233 static int jh057n_get_modes(struct drm_panel *panel,
234 struct drm_connector *connector)
236 struct jh057n *ctx = panel_to_jh057n(panel);
237 struct drm_display_mode *mode;
239 mode = drm_mode_duplicate(connector->dev, &default_mode);
240 if (!mode) {
241 DRM_DEV_ERROR(ctx->dev, "Failed to add mode %ux%u@%u\n",
242 default_mode.hdisplay, default_mode.vdisplay,
243 default_mode.vrefresh);
244 return -ENOMEM;
247 drm_mode_set_name(mode);
249 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
250 connector->display_info.width_mm = mode->width_mm;
251 connector->display_info.height_mm = mode->height_mm;
252 drm_mode_probed_add(connector, mode);
254 return 1;
257 static const struct drm_panel_funcs jh057n_drm_funcs = {
258 .disable = jh057n_disable,
259 .unprepare = jh057n_unprepare,
260 .prepare = jh057n_prepare,
261 .enable = jh057n_enable,
262 .get_modes = jh057n_get_modes,
265 static int allpixelson_set(void *data, u64 val)
267 struct jh057n *ctx = data;
268 struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
270 DRM_DEV_DEBUG_DRIVER(ctx->dev, "Setting all pixels on\n");
271 dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
272 msleep(val * 1000);
273 /* Reset the panel to get video back */
274 drm_panel_disable(&ctx->panel);
275 drm_panel_unprepare(&ctx->panel);
276 drm_panel_prepare(&ctx->panel);
277 drm_panel_enable(&ctx->panel);
279 return 0;
282 DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
283 allpixelson_set, "%llu\n");
285 static void jh057n_debugfs_init(struct jh057n *ctx)
287 ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
289 debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
290 &allpixelson_fops);
293 static void jh057n_debugfs_remove(struct jh057n *ctx)
295 debugfs_remove_recursive(ctx->debugfs);
296 ctx->debugfs = NULL;
299 static int jh057n_probe(struct mipi_dsi_device *dsi)
301 struct device *dev = &dsi->dev;
302 struct jh057n *ctx;
303 int ret;
305 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
306 if (!ctx)
307 return -ENOMEM;
309 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
310 if (IS_ERR(ctx->reset_gpio)) {
311 DRM_DEV_ERROR(dev, "cannot get reset gpio\n");
312 return PTR_ERR(ctx->reset_gpio);
315 mipi_dsi_set_drvdata(dsi, ctx);
317 ctx->dev = dev;
319 dsi->lanes = 4;
320 dsi->format = MIPI_DSI_FMT_RGB888;
321 dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
322 MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE;
324 ctx->vcc = devm_regulator_get(dev, "vcc");
325 if (IS_ERR(ctx->vcc)) {
326 ret = PTR_ERR(ctx->vcc);
327 if (ret != -EPROBE_DEFER)
328 DRM_DEV_ERROR(dev,
329 "Failed to request vcc regulator: %d\n",
330 ret);
331 return ret;
333 ctx->iovcc = devm_regulator_get(dev, "iovcc");
334 if (IS_ERR(ctx->iovcc)) {
335 ret = PTR_ERR(ctx->iovcc);
336 if (ret != -EPROBE_DEFER)
337 DRM_DEV_ERROR(dev,
338 "Failed to request iovcc regulator: %d\n",
339 ret);
340 return ret;
343 drm_panel_init(&ctx->panel, dev, &jh057n_drm_funcs,
344 DRM_MODE_CONNECTOR_DSI);
346 ret = drm_panel_of_backlight(&ctx->panel);
347 if (ret)
348 return ret;
350 drm_panel_add(&ctx->panel);
352 ret = mipi_dsi_attach(dsi);
353 if (ret < 0) {
354 DRM_DEV_ERROR(dev,
355 "mipi_dsi_attach failed (%d). Is host ready?\n",
356 ret);
357 drm_panel_remove(&ctx->panel);
358 return ret;
361 DRM_DEV_INFO(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
362 default_mode.hdisplay, default_mode.vdisplay,
363 default_mode.vrefresh,
364 mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
366 jh057n_debugfs_init(ctx);
367 return 0;
370 static void jh057n_shutdown(struct mipi_dsi_device *dsi)
372 struct jh057n *ctx = mipi_dsi_get_drvdata(dsi);
373 int ret;
375 ret = drm_panel_unprepare(&ctx->panel);
376 if (ret < 0)
377 DRM_DEV_ERROR(&dsi->dev, "Failed to unprepare panel: %d\n",
378 ret);
380 ret = drm_panel_disable(&ctx->panel);
381 if (ret < 0)
382 DRM_DEV_ERROR(&dsi->dev, "Failed to disable panel: %d\n",
383 ret);
386 static int jh057n_remove(struct mipi_dsi_device *dsi)
388 struct jh057n *ctx = mipi_dsi_get_drvdata(dsi);
389 int ret;
391 jh057n_shutdown(dsi);
393 ret = mipi_dsi_detach(dsi);
394 if (ret < 0)
395 DRM_DEV_ERROR(&dsi->dev, "Failed to detach from DSI host: %d\n",
396 ret);
398 drm_panel_remove(&ctx->panel);
400 jh057n_debugfs_remove(ctx);
402 return 0;
405 static const struct of_device_id jh057n_of_match[] = {
406 { .compatible = "rocktech,jh057n00900" },
407 { /* sentinel */ }
409 MODULE_DEVICE_TABLE(of, jh057n_of_match);
411 static struct mipi_dsi_driver jh057n_driver = {
412 .probe = jh057n_probe,
413 .remove = jh057n_remove,
414 .shutdown = jh057n_shutdown,
415 .driver = {
416 .name = DRV_NAME,
417 .of_match_table = jh057n_of_match,
420 module_mipi_dsi_driver(jh057n_driver);
422 MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
423 MODULE_DESCRIPTION("DRM driver for Rocktech JH057N00900 MIPI DSI panel");
424 MODULE_LICENSE("GPL v2");