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