1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2019, The Linux Foundation. All rights reserved. 4 */ 5 6 #include <linux/delay.h> 7 #include <linux/module.h> 8 #include <linux/of_device.h> 9 #include <linux/gpio/consumer.h> 10 #include <linux/regulator/consumer.h> 11 12 #include <video/mipi_display.h> 13 14 #include <drm/drm_mipi_dsi.h> 15 #include <drm/drm_modes.h> 16 #include <drm/drm_panel.h> 17 #include <drm/drm_print.h> 18 19 struct visionox_rm69299 { 20 struct drm_panel panel; 21 struct regulator_bulk_data supplies[2]; 22 struct gpio_desc *reset_gpio; 23 struct mipi_dsi_device *dsi; 24 bool prepared; 25 bool enabled; 26 }; 27 28 static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel) 29 { 30 return container_of(panel, struct visionox_rm69299, panel); 31 } 32 33 static int visionox_rm69299_power_on(struct visionox_rm69299 *ctx) 34 { 35 int ret; 36 37 ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 38 if (ret < 0) 39 return ret; 40 41 /* 42 * Reset sequence of visionox panel requires the panel to be 43 * out of reset for 10ms, followed by being held in reset 44 * for 10ms and then out again 45 */ 46 gpiod_set_value(ctx->reset_gpio, 1); 47 usleep_range(10000, 20000); 48 gpiod_set_value(ctx->reset_gpio, 0); 49 usleep_range(10000, 20000); 50 gpiod_set_value(ctx->reset_gpio, 1); 51 usleep_range(10000, 20000); 52 53 return 0; 54 } 55 56 static int visionox_rm69299_power_off(struct visionox_rm69299 *ctx) 57 { 58 gpiod_set_value(ctx->reset_gpio, 0); 59 60 return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 61 } 62 63 static int visionox_rm69299_unprepare(struct drm_panel *panel) 64 { 65 struct visionox_rm69299 *ctx = panel_to_ctx(panel); 66 int ret; 67 68 ctx->dsi->mode_flags = 0; 69 70 ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0); 71 if (ret < 0) 72 DRM_DEV_ERROR(ctx->panel.dev, 73 "set_display_off cmd failed ret = %d\n", ret); 74 75 /* 120ms delay required here as per DCS spec */ 76 msleep(120); 77 78 ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0); 79 if (ret < 0) { 80 DRM_DEV_ERROR(ctx->panel.dev, 81 "enter_sleep cmd failed ret = %d\n", ret); 82 } 83 84 ret = visionox_rm69299_power_off(ctx); 85 86 ctx->prepared = false; 87 return ret; 88 } 89 90 static int visionox_rm69299_prepare(struct drm_panel *panel) 91 { 92 struct visionox_rm69299 *ctx = panel_to_ctx(panel); 93 int ret; 94 95 if (ctx->prepared) 96 return 0; 97 98 ret = visionox_rm69299_power_on(ctx); 99 if (ret < 0) 100 return ret; 101 102 ctx->dsi->mode_flags |= MIPI_DSI_MODE_LPM; 103 104 ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xfe, 0x00 }, 2); 105 if (ret < 0) { 106 DRM_DEV_ERROR(ctx->panel.dev, 107 "cmd set tx 0 failed, ret = %d\n", ret); 108 goto power_off; 109 } 110 111 ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0xc2, 0x08 }, 2); 112 if (ret < 0) { 113 DRM_DEV_ERROR(ctx->panel.dev, 114 "cmd set tx 1 failed, ret = %d\n", ret); 115 goto power_off; 116 } 117 118 ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x35, 0x00 }, 2); 119 if (ret < 0) { 120 DRM_DEV_ERROR(ctx->panel.dev, 121 "cmd set tx 2 failed, ret = %d\n", ret); 122 goto power_off; 123 } 124 125 ret = mipi_dsi_dcs_write_buffer(ctx->dsi, (u8[]) { 0x51, 0xff }, 2); 126 if (ret < 0) { 127 DRM_DEV_ERROR(ctx->panel.dev, 128 "cmd set tx 3 failed, ret = %d\n", ret); 129 goto power_off; 130 } 131 132 ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0); 133 if (ret < 0) { 134 DRM_DEV_ERROR(ctx->panel.dev, 135 "exit_sleep_mode cmd failed ret = %d\n", ret); 136 goto power_off; 137 } 138 139 /* Per DSI spec wait 120ms after sending exit sleep DCS command */ 140 msleep(120); 141 142 ret = mipi_dsi_dcs_write(ctx->dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0); 143 if (ret < 0) { 144 DRM_DEV_ERROR(ctx->panel.dev, 145 "set_display_on cmd failed ret = %d\n", ret); 146 goto power_off; 147 } 148 149 /* Per DSI spec wait 120ms after sending set_display_on DCS command */ 150 msleep(120); 151 152 ctx->prepared = true; 153 154 return 0; 155 156 power_off: 157 return ret; 158 } 159 160 static const struct drm_display_mode visionox_rm69299_1080x2248_60hz = { 161 .name = "1080x2248", 162 .clock = 158695, 163 .hdisplay = 1080, 164 .hsync_start = 1080 + 26, 165 .hsync_end = 1080 + 26 + 2, 166 .htotal = 1080 + 26 + 2 + 36, 167 .vdisplay = 2248, 168 .vsync_start = 2248 + 56, 169 .vsync_end = 2248 + 56 + 4, 170 .vtotal = 2248 + 56 + 4 + 4, 171 .flags = 0, 172 }; 173 174 static int visionox_rm69299_get_modes(struct drm_panel *panel, 175 struct drm_connector *connector) 176 { 177 struct visionox_rm69299 *ctx = panel_to_ctx(panel); 178 struct drm_display_mode *mode; 179 180 mode = drm_mode_create(connector->dev); 181 if (!mode) { 182 DRM_DEV_ERROR(ctx->panel.dev, 183 "failed to create a new display mode\n"); 184 return 0; 185 } 186 187 connector->display_info.width_mm = 74; 188 connector->display_info.height_mm = 131; 189 drm_mode_copy(mode, &visionox_rm69299_1080x2248_60hz); 190 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 191 drm_mode_probed_add(connector, mode); 192 193 return 1; 194 } 195 196 static const struct drm_panel_funcs visionox_rm69299_drm_funcs = { 197 .unprepare = visionox_rm69299_unprepare, 198 .prepare = visionox_rm69299_prepare, 199 .get_modes = visionox_rm69299_get_modes, 200 }; 201 202 static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) 203 { 204 struct device *dev = &dsi->dev; 205 struct visionox_rm69299 *ctx; 206 int ret; 207 208 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 209 if (!ctx) 210 return -ENOMEM; 211 212 mipi_dsi_set_drvdata(dsi, ctx); 213 214 ctx->panel.dev = dev; 215 ctx->dsi = dsi; 216 217 ctx->supplies[0].supply = "vdda"; 218 ctx->supplies[1].supply = "vdd3p3"; 219 220 ret = devm_regulator_bulk_get(ctx->panel.dev, ARRAY_SIZE(ctx->supplies), 221 ctx->supplies); 222 if (ret < 0) 223 return ret; 224 225 ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, 226 "reset", GPIOD_OUT_LOW); 227 if (IS_ERR(ctx->reset_gpio)) { 228 DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", 229 PTR_ERR(ctx->reset_gpio)); 230 return PTR_ERR(ctx->reset_gpio); 231 } 232 233 drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs, 234 DRM_MODE_CONNECTOR_DSI); 235 ctx->panel.dev = dev; 236 ctx->panel.funcs = &visionox_rm69299_drm_funcs; 237 drm_panel_add(&ctx->panel); 238 239 dsi->lanes = 4; 240 dsi->format = MIPI_DSI_FMT_RGB888; 241 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | 242 MIPI_DSI_CLOCK_NON_CONTINUOUS; 243 ret = mipi_dsi_attach(dsi); 244 if (ret < 0) { 245 DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret); 246 goto err_dsi_attach; 247 } 248 249 ret = regulator_set_load(ctx->supplies[0].consumer, 32000); 250 if (ret) { 251 DRM_DEV_ERROR(dev, 252 "regulator set load failed for vdda supply ret = %d\n", 253 ret); 254 goto err_set_load; 255 } 256 257 ret = regulator_set_load(ctx->supplies[1].consumer, 13200); 258 if (ret) { 259 DRM_DEV_ERROR(dev, 260 "regulator set load failed for vdd3p3 supply ret = %d\n", 261 ret); 262 goto err_set_load; 263 } 264 265 return 0; 266 267 err_set_load: 268 mipi_dsi_detach(dsi); 269 err_dsi_attach: 270 drm_panel_remove(&ctx->panel); 271 return ret; 272 } 273 274 static int visionox_rm69299_remove(struct mipi_dsi_device *dsi) 275 { 276 struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi); 277 278 mipi_dsi_detach(ctx->dsi); 279 mipi_dsi_device_unregister(ctx->dsi); 280 281 drm_panel_remove(&ctx->panel); 282 return 0; 283 } 284 285 static const struct of_device_id visionox_rm69299_of_match[] = { 286 { .compatible = "visionox,rm69299-1080p-display", }, 287 { /* sentinel */ } 288 }; 289 MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match); 290 291 static struct mipi_dsi_driver visionox_rm69299_driver = { 292 .driver = { 293 .name = "panel-visionox-rm69299", 294 .of_match_table = visionox_rm69299_of_match, 295 }, 296 .probe = visionox_rm69299_probe, 297 .remove = visionox_rm69299_remove, 298 }; 299 module_mipi_dsi_driver(visionox_rm69299_driver); 300 301 MODULE_DESCRIPTION("Visionox RM69299 DSI Panel Driver"); 302 MODULE_LICENSE("GPL v2"); 303