Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v5.8-rc4 303 lines 7.5 kB view raw
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 19struct 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 28static inline struct visionox_rm69299 *panel_to_ctx(struct drm_panel *panel) 29{ 30 return container_of(panel, struct visionox_rm69299, panel); 31} 32 33static 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 56static 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 63static 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 90static 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 156power_off: 157 return ret; 158} 159 160static 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 .vrefresh = 60, 172 .flags = 0, 173}; 174 175static int visionox_rm69299_get_modes(struct drm_panel *panel, 176 struct drm_connector *connector) 177{ 178 struct visionox_rm69299 *ctx = panel_to_ctx(panel); 179 struct drm_display_mode *mode; 180 181 mode = drm_mode_create(connector->dev); 182 if (!mode) { 183 DRM_DEV_ERROR(ctx->panel.dev, 184 "failed to create a new display mode\n"); 185 return 0; 186 } 187 188 connector->display_info.width_mm = 74; 189 connector->display_info.height_mm = 131; 190 drm_mode_copy(mode, &visionox_rm69299_1080x2248_60hz); 191 mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 192 drm_mode_probed_add(connector, mode); 193 194 return 1; 195} 196 197static const struct drm_panel_funcs visionox_rm69299_drm_funcs = { 198 .unprepare = visionox_rm69299_unprepare, 199 .prepare = visionox_rm69299_prepare, 200 .get_modes = visionox_rm69299_get_modes, 201}; 202 203static int visionox_rm69299_probe(struct mipi_dsi_device *dsi) 204{ 205 struct device *dev = &dsi->dev; 206 struct visionox_rm69299 *ctx; 207 int ret; 208 209 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 210 if (!ctx) 211 return -ENOMEM; 212 213 mipi_dsi_set_drvdata(dsi, ctx); 214 215 ctx->panel.dev = dev; 216 ctx->dsi = dsi; 217 218 ctx->supplies[0].supply = "vdda"; 219 ctx->supplies[1].supply = "vdd3p3"; 220 221 ret = devm_regulator_bulk_get(ctx->panel.dev, ARRAY_SIZE(ctx->supplies), 222 ctx->supplies); 223 if (ret < 0) 224 return ret; 225 226 ctx->reset_gpio = devm_gpiod_get(ctx->panel.dev, 227 "reset", GPIOD_OUT_LOW); 228 if (IS_ERR(ctx->reset_gpio)) { 229 DRM_DEV_ERROR(dev, "cannot get reset gpio %ld\n", 230 PTR_ERR(ctx->reset_gpio)); 231 return PTR_ERR(ctx->reset_gpio); 232 } 233 234 drm_panel_init(&ctx->panel, dev, &visionox_rm69299_drm_funcs, 235 DRM_MODE_CONNECTOR_DSI); 236 ctx->panel.dev = dev; 237 ctx->panel.funcs = &visionox_rm69299_drm_funcs; 238 drm_panel_add(&ctx->panel); 239 240 dsi->lanes = 4; 241 dsi->format = MIPI_DSI_FMT_RGB888; 242 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM | 243 MIPI_DSI_CLOCK_NON_CONTINUOUS; 244 ret = mipi_dsi_attach(dsi); 245 if (ret < 0) { 246 DRM_DEV_ERROR(dev, "dsi attach failed ret = %d\n", ret); 247 goto err_dsi_attach; 248 } 249 250 ret = regulator_set_load(ctx->supplies[0].consumer, 32000); 251 if (ret) { 252 DRM_DEV_ERROR(dev, 253 "regulator set load failed for vdda supply ret = %d\n", 254 ret); 255 goto err_set_load; 256 } 257 258 ret = regulator_set_load(ctx->supplies[1].consumer, 13200); 259 if (ret) { 260 DRM_DEV_ERROR(dev, 261 "regulator set load failed for vdd3p3 supply ret = %d\n", 262 ret); 263 goto err_set_load; 264 } 265 266 return 0; 267 268err_set_load: 269 mipi_dsi_detach(dsi); 270err_dsi_attach: 271 drm_panel_remove(&ctx->panel); 272 return ret; 273} 274 275static int visionox_rm69299_remove(struct mipi_dsi_device *dsi) 276{ 277 struct visionox_rm69299 *ctx = mipi_dsi_get_drvdata(dsi); 278 279 mipi_dsi_detach(ctx->dsi); 280 mipi_dsi_device_unregister(ctx->dsi); 281 282 drm_panel_remove(&ctx->panel); 283 return 0; 284} 285 286static const struct of_device_id visionox_rm69299_of_match[] = { 287 { .compatible = "visionox,rm69299-1080p-display", }, 288 { /* sentinel */ } 289}; 290MODULE_DEVICE_TABLE(of, visionox_rm69299_of_match); 291 292static struct mipi_dsi_driver visionox_rm69299_driver = { 293 .driver = { 294 .name = "panel-visionox-rm69299", 295 .of_match_table = visionox_rm69299_of_match, 296 }, 297 .probe = visionox_rm69299_probe, 298 .remove = visionox_rm69299_remove, 299}; 300module_mipi_dsi_driver(visionox_rm69299_driver); 301 302MODULE_DESCRIPTION("Visionox RM69299 DSI Panel Driver"); 303MODULE_LICENSE("GPL v2");