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->panel.dev = dev; 197 ctx->dsi = dsi; 198 199 ctx->supplies[0].supply = "vdda"; 200 ctx->supplies[0].init_load_uA = 32000; 201 ctx->supplies[1].supply = "vdd3p3"; 202 ctx->supplies[1].init_load_uA = 13200; 203 204 ret = devm_regulator_bulk_get(ctx->panel.dev, ARRAY_SIZE(ctx->supplies), 205 ctx->supplies); 206 if (ret < 0) 207 return ret; 208 209 ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, 210 "reset", GPIOD_OUT_LOW); 211 if (IS_ERR(ctx->reset_gpio)) { 212 dev_err(dev, "cannot get reset gpio %ld\n", PTR_ERR(ctx->reset_gpio)); 213 return PTR_ERR(ctx->reset_gpio); 214 } 215 216 drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs, 217 DRM_MODE_CONNECTOR_DSI); 218 ctx->panel.dev = dev; 219 ctx->panel.funcs = &visionox_rm69299_drm_funcs; 220 drm_panel_add(&ctx->panel); 221 222 dsi->lanes = 4; 223 dsi->format = MIPI_DSI_FMT_RGB888; 224 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | 225 MIPI_DSI_CLOCK_NON_CONTINUOUS; 226 ret = mipi_dsi_attach(dsi); 227 if (ret < 0) { 228 dev_err(dev, "dsi attach failed ret = %d\n", ret); 229 goto err_dsi_attach; 230 } 231 232 return 0; 233 234 err_dsi_attach: 235 drm_panel_remove(&ctx->panel); 236 return ret; 237 } 238 239 static void visionox_rm69299_remove(struct mipi_dsi_device *dsi) 240 { 241 struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi); 242 243 mipi_dsi_detach(ctx->dsi); 244 drm_panel_remove(&ctx->panel); 245 } 246 247 static const struct of_device_id visionox_rm69299_of_match[] = { 248 { .compatible = "visionox,rm69299-1080p-display", }, 249 { /* sentinel */ } 250 }; 251 MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match); 252 253 static struct mipi_dsi_driver visionox_rm69299_driver = { 254 .driver = { 255 .name = "panel-visionox-rm69299", 256 .of_match_table = visionox_rm69299_of_match, 257 }, 258 .probe = visionox_rm69299_probe, 259 .remove = visionox_rm69299_remove, 260 }; 261 module_mipi_dsi_driver(visionox_rm69299_driver); 262 263 MODULE_DESCRIPTION("Visionox RM69299 DSI Panel Driver"); 264 MODULE_LICENSE("GPL v2"); 265