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 v6.15-rc4 241 lines 6.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0-only 2// Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: 3// Copyright (c) 2013, The Linux Foundation. All rights reserved. 4// Copyright (c) 2024, Neil Armstrong <neil.armstrong@linaro.org> 5 6#include <linux/delay.h> 7#include <linux/gpio/consumer.h> 8#include <linux/module.h> 9#include <linux/of.h> 10#include <linux/regulator/consumer.h> 11 12#include <drm/drm_mipi_dsi.h> 13#include <drm/drm_modes.h> 14#include <drm/drm_panel.h> 15#include <drm/drm_probe_helper.h> 16 17struct boe_tv101wum_ll2 { 18 struct drm_panel panel; 19 struct mipi_dsi_device *dsi; 20 struct gpio_desc *reset_gpio; 21 struct regulator_bulk_data *supplies; 22}; 23 24static const struct regulator_bulk_data boe_tv101wum_ll2_supplies[] = { 25 { .supply = "vsp" }, 26 { .supply = "vsn" }, 27}; 28 29static inline struct boe_tv101wum_ll2 *to_boe_tv101wum_ll2(struct drm_panel *panel) 30{ 31 return container_of(panel, struct boe_tv101wum_ll2, panel); 32} 33 34static void boe_tv101wum_ll2_reset(struct boe_tv101wum_ll2 *ctx) 35{ 36 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 37 usleep_range(5000, 6000); 38 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 39 usleep_range(5000, 6000); 40 gpiod_set_value_cansleep(ctx->reset_gpio, 0); 41 42 msleep(120); 43} 44 45static int boe_tv101wum_ll2_on(struct boe_tv101wum_ll2 *ctx) 46{ 47 struct mipi_dsi_device *dsi = ctx->dsi; 48 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 49 50 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 51 52 mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 53 54 mipi_dsi_msleep(&dsi_ctx, 120); 55 56 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0e); 57 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x80, 0xff, 0x81, 0x68, 0x6c, 0x22, 58 0x6d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00); 59 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x23); 60 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x90, 0x00, 0x00); 61 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x94, 0x2c, 0x00); 62 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x19); 63 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0xa2, 0x38); 64 65 mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x5a, 0x0c); 66 mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x80, 0xfd); 67 mipi_dsi_generic_write_seq_multi(&dsi_ctx, 0x50, 0x00); 68 69 mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 70 71 mipi_dsi_msleep(&dsi_ctx, 20); 72 73 return dsi_ctx.accum_err; 74} 75 76static void boe_tv101wum_ll2_off(struct boe_tv101wum_ll2 *ctx) 77{ 78 struct mipi_dsi_device *dsi = ctx->dsi; 79 struct mipi_dsi_multi_context dsi_ctx = { .dsi = dsi }; 80 81 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 82 83 mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 84 85 mipi_dsi_msleep(&dsi_ctx, 70); 86 87 mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 88 89 mipi_dsi_msleep(&dsi_ctx, 20); 90 91 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x04, 0x5a); 92 mipi_dsi_dcs_write_seq_multi(&dsi_ctx, 0x05, 0x5a); 93 94 mipi_dsi_msleep(&dsi_ctx, 150); 95} 96 97static int boe_tv101wum_ll2_prepare(struct drm_panel *panel) 98{ 99 struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel); 100 int ret; 101 102 ret = regulator_bulk_enable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 103 ctx->supplies); 104 if (ret < 0) 105 return ret; 106 107 boe_tv101wum_ll2_reset(ctx); 108 109 ret = boe_tv101wum_ll2_on(ctx); 110 if (ret < 0) { 111 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 112 regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 113 ctx->supplies); 114 return ret; 115 } 116 117 return 0; 118} 119 120static int boe_tv101wum_ll2_unprepare(struct drm_panel *panel) 121{ 122 struct boe_tv101wum_ll2 *ctx = to_boe_tv101wum_ll2(panel); 123 124 /* Ignore errors on failure, in any case set gpio and disable regulators */ 125 boe_tv101wum_ll2_off(ctx); 126 127 gpiod_set_value_cansleep(ctx->reset_gpio, 1); 128 129 regulator_bulk_disable(ARRAY_SIZE(boe_tv101wum_ll2_supplies), 130 ctx->supplies); 131 132 return 0; 133} 134 135static const struct drm_display_mode boe_tv101wum_ll2_mode = { 136 .clock = (1200 + 27 + 8 + 12) * (1920 + 155 + 8 + 32) * 60 / 1000, 137 .hdisplay = 1200, 138 .hsync_start = 1200 + 27, 139 .hsync_end = 1200 + 27 + 8, 140 .htotal = 1200 + 27 + 8 + 12, 141 .vdisplay = 1920, 142 .vsync_start = 1920 + 155, 143 .vsync_end = 1920 + 155 + 8, 144 .vtotal = 1920 + 155 + 8 + 32, 145 .width_mm = 136, 146 .height_mm = 217, 147 .type = DRM_MODE_TYPE_DRIVER, 148}; 149 150static int boe_tv101wum_ll2_get_modes(struct drm_panel *panel, 151 struct drm_connector *connector) 152{ 153 /* We do not set display_info.bpc since unset value is bpc=8 by default */ 154 return drm_connector_helper_get_modes_fixed(connector, &boe_tv101wum_ll2_mode); 155} 156 157static const struct drm_panel_funcs boe_tv101wum_ll2_panel_funcs = { 158 .prepare = boe_tv101wum_ll2_prepare, 159 .unprepare = boe_tv101wum_ll2_unprepare, 160 .get_modes = boe_tv101wum_ll2_get_modes, 161}; 162 163static int boe_tv101wum_ll2_probe(struct mipi_dsi_device *dsi) 164{ 165 struct device *dev = &dsi->dev; 166 struct boe_tv101wum_ll2 *ctx; 167 int ret; 168 169 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 170 if (!ctx) 171 return -ENOMEM; 172 173 ret = devm_regulator_bulk_get_const(&dsi->dev, 174 ARRAY_SIZE(boe_tv101wum_ll2_supplies), 175 boe_tv101wum_ll2_supplies, 176 &ctx->supplies); 177 if (ret < 0) 178 return ret; 179 180 ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 181 if (IS_ERR(ctx->reset_gpio)) 182 return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 183 "Failed to get reset-gpios\n"); 184 185 ctx->dsi = dsi; 186 mipi_dsi_set_drvdata(dsi, ctx); 187 188 dsi->lanes = 4; 189 dsi->format = MIPI_DSI_FMT_RGB888; 190 dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 191 MIPI_DSI_MODE_VIDEO_HSE; 192 193 drm_panel_init(&ctx->panel, dev, &boe_tv101wum_ll2_panel_funcs, 194 DRM_MODE_CONNECTOR_DSI); 195 ctx->panel.prepare_prev_first = true; 196 197 ret = drm_panel_of_backlight(&ctx->panel); 198 if (ret) 199 return dev_err_probe(dev, ret, "Failed to get backlight\n"); 200 201 drm_panel_add(&ctx->panel); 202 203 ret = mipi_dsi_attach(dsi); 204 if (ret < 0) { 205 drm_panel_remove(&ctx->panel); 206 return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 207 } 208 209 return 0; 210} 211 212static void boe_tv101wum_ll2_remove(struct mipi_dsi_device *dsi) 213{ 214 struct boe_tv101wum_ll2 *ctx = mipi_dsi_get_drvdata(dsi); 215 int ret; 216 217 ret = mipi_dsi_detach(dsi); 218 if (ret < 0) 219 dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 220 221 drm_panel_remove(&ctx->panel); 222} 223 224static const struct of_device_id boe_tv101wum_ll2_of_match[] = { 225 { .compatible = "boe,tv101wum-ll2" }, 226 { /* sentinel */ } 227}; 228MODULE_DEVICE_TABLE(of, boe_tv101wum_ll2_of_match); 229 230static struct mipi_dsi_driver boe_tv101wum_ll2_driver = { 231 .probe = boe_tv101wum_ll2_probe, 232 .remove = boe_tv101wum_ll2_remove, 233 .driver = { 234 .name = "panel-boe-tv101wum_ll2", 235 .of_match_table = boe_tv101wum_ll2_of_match, 236 }, 237}; 238module_mipi_dsi_driver(boe_tv101wum_ll2_driver); 239 240MODULE_DESCRIPTION("DRM driver for BOE TV101WUM-LL2 Panel"); 241MODULE_LICENSE("GPL");