1*ac488854SAnton Bambura // SPDX-License-Identifier: GPL-2.0-only 2*ac488854SAnton Bambura 3*ac488854SAnton Bambura #include <linux/array_size.h> 4*ac488854SAnton Bambura #include <linux/delay.h> 5*ac488854SAnton Bambura #include <linux/err.h> 6*ac488854SAnton Bambura #include <linux/gpio/consumer.h> 7*ac488854SAnton Bambura #include <linux/mod_devicetable.h> 8*ac488854SAnton Bambura #include <linux/module.h> 9*ac488854SAnton Bambura #include <linux/property.h> 10*ac488854SAnton Bambura #include <linux/regulator/consumer.h> 11*ac488854SAnton Bambura 12*ac488854SAnton Bambura #include <video/mipi_display.h> 13*ac488854SAnton Bambura 14*ac488854SAnton Bambura #include <drm/drm_mipi_dsi.h> 15*ac488854SAnton Bambura #include <drm/drm_modes.h> 16*ac488854SAnton Bambura #include <drm/drm_panel.h> 17*ac488854SAnton Bambura #include <drm/drm_probe_helper.h> 18*ac488854SAnton Bambura 19*ac488854SAnton Bambura struct samsung_ltl106hl02 { 20*ac488854SAnton Bambura struct drm_panel panel; 21*ac488854SAnton Bambura struct mipi_dsi_device *dsi; 22*ac488854SAnton Bambura 23*ac488854SAnton Bambura struct regulator *supply; 24*ac488854SAnton Bambura struct gpio_desc *reset_gpio; 25*ac488854SAnton Bambura }; 26*ac488854SAnton Bambura 27*ac488854SAnton Bambura static inline struct samsung_ltl106hl02 *to_samsung_ltl106hl02(struct drm_panel *panel) 28*ac488854SAnton Bambura { 29*ac488854SAnton Bambura return container_of(panel, struct samsung_ltl106hl02, panel); 30*ac488854SAnton Bambura } 31*ac488854SAnton Bambura 32*ac488854SAnton Bambura static void samsung_ltl106hl02_reset(struct samsung_ltl106hl02 *ctx) 33*ac488854SAnton Bambura { 34*ac488854SAnton Bambura gpiod_set_value_cansleep(ctx->reset_gpio, 1); 35*ac488854SAnton Bambura usleep_range(10000, 11000); 36*ac488854SAnton Bambura gpiod_set_value_cansleep(ctx->reset_gpio, 0); 37*ac488854SAnton Bambura usleep_range(2000, 3000); 38*ac488854SAnton Bambura } 39*ac488854SAnton Bambura 40*ac488854SAnton Bambura static int samsung_ltl106hl02_prepare(struct drm_panel *panel) 41*ac488854SAnton Bambura { 42*ac488854SAnton Bambura struct samsung_ltl106hl02 *ctx = to_samsung_ltl106hl02(panel); 43*ac488854SAnton Bambura struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 44*ac488854SAnton Bambura struct device *dev = &ctx->dsi->dev; 45*ac488854SAnton Bambura int ret; 46*ac488854SAnton Bambura 47*ac488854SAnton Bambura ret = regulator_enable(ctx->supply); 48*ac488854SAnton Bambura if (ret < 0) { 49*ac488854SAnton Bambura dev_err(dev, "failed to enable power supply %d\n", ret); 50*ac488854SAnton Bambura return ret; 51*ac488854SAnton Bambura } 52*ac488854SAnton Bambura 53*ac488854SAnton Bambura if (ctx->reset_gpio) 54*ac488854SAnton Bambura samsung_ltl106hl02_reset(ctx); 55*ac488854SAnton Bambura 56*ac488854SAnton Bambura mipi_dsi_dcs_exit_sleep_mode_multi(&dsi_ctx); 57*ac488854SAnton Bambura mipi_dsi_msleep(&dsi_ctx, 70); 58*ac488854SAnton Bambura 59*ac488854SAnton Bambura mipi_dsi_dcs_set_display_on_multi(&dsi_ctx); 60*ac488854SAnton Bambura mipi_dsi_msleep(&dsi_ctx, 5); 61*ac488854SAnton Bambura 62*ac488854SAnton Bambura return dsi_ctx.accum_err; 63*ac488854SAnton Bambura } 64*ac488854SAnton Bambura 65*ac488854SAnton Bambura static int samsung_ltl106hl02_unprepare(struct drm_panel *panel) 66*ac488854SAnton Bambura { 67*ac488854SAnton Bambura struct samsung_ltl106hl02 *ctx = to_samsung_ltl106hl02(panel); 68*ac488854SAnton Bambura struct mipi_dsi_multi_context dsi_ctx = { .dsi = ctx->dsi }; 69*ac488854SAnton Bambura 70*ac488854SAnton Bambura mipi_dsi_dcs_set_display_off_multi(&dsi_ctx); 71*ac488854SAnton Bambura mipi_dsi_msleep(&dsi_ctx, 50); 72*ac488854SAnton Bambura mipi_dsi_dcs_enter_sleep_mode_multi(&dsi_ctx); 73*ac488854SAnton Bambura mipi_dsi_msleep(&dsi_ctx, 150); 74*ac488854SAnton Bambura 75*ac488854SAnton Bambura if (ctx->reset_gpio) 76*ac488854SAnton Bambura gpiod_set_value_cansleep(ctx->reset_gpio, 1); 77*ac488854SAnton Bambura 78*ac488854SAnton Bambura regulator_disable(ctx->supply); 79*ac488854SAnton Bambura 80*ac488854SAnton Bambura return 0; 81*ac488854SAnton Bambura } 82*ac488854SAnton Bambura 83*ac488854SAnton Bambura static const struct drm_display_mode samsung_ltl106hl02_mode = { 84*ac488854SAnton Bambura .clock = (1920 + 32 + 32 + 64) * (1080 + 6 + 3 + 22) * 60 / 1000, 85*ac488854SAnton Bambura .hdisplay = 1920, 86*ac488854SAnton Bambura .hsync_start = 1920 + 32, 87*ac488854SAnton Bambura .hsync_end = 1920 + 32 + 32, 88*ac488854SAnton Bambura .htotal = 1920 + 32 + 32 + 64, 89*ac488854SAnton Bambura .vdisplay = 1080, 90*ac488854SAnton Bambura .vsync_start = 1080 + 6, 91*ac488854SAnton Bambura .vsync_end = 1080 + 6 + 3, 92*ac488854SAnton Bambura .vtotal = 1080 + 6 + 3 + 22, 93*ac488854SAnton Bambura .width_mm = 235, 94*ac488854SAnton Bambura .height_mm = 132, 95*ac488854SAnton Bambura .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, 96*ac488854SAnton Bambura }; 97*ac488854SAnton Bambura 98*ac488854SAnton Bambura static int samsung_ltl106hl02_get_modes(struct drm_panel *panel, 99*ac488854SAnton Bambura struct drm_connector *connector) 100*ac488854SAnton Bambura { 101*ac488854SAnton Bambura return drm_connector_helper_get_modes_fixed(connector, &samsung_ltl106hl02_mode); 102*ac488854SAnton Bambura } 103*ac488854SAnton Bambura 104*ac488854SAnton Bambura static const struct drm_panel_funcs samsung_ltl106hl02_panel_funcs = { 105*ac488854SAnton Bambura .prepare = samsung_ltl106hl02_prepare, 106*ac488854SAnton Bambura .unprepare = samsung_ltl106hl02_unprepare, 107*ac488854SAnton Bambura .get_modes = samsung_ltl106hl02_get_modes, 108*ac488854SAnton Bambura }; 109*ac488854SAnton Bambura 110*ac488854SAnton Bambura static int samsung_ltl106hl02_probe(struct mipi_dsi_device *dsi) 111*ac488854SAnton Bambura { 112*ac488854SAnton Bambura struct device *dev = &dsi->dev; 113*ac488854SAnton Bambura struct samsung_ltl106hl02 *ctx; 114*ac488854SAnton Bambura int ret; 115*ac488854SAnton Bambura 116*ac488854SAnton Bambura ctx = devm_drm_panel_alloc(dev, struct samsung_ltl106hl02, panel, 117*ac488854SAnton Bambura &samsung_ltl106hl02_panel_funcs, 118*ac488854SAnton Bambura DRM_MODE_CONNECTOR_DSI); 119*ac488854SAnton Bambura if (IS_ERR(ctx)) 120*ac488854SAnton Bambura return PTR_ERR(ctx); 121*ac488854SAnton Bambura 122*ac488854SAnton Bambura ctx->supply = devm_regulator_get(dev, "power"); 123*ac488854SAnton Bambura if (IS_ERR(ctx->supply)) 124*ac488854SAnton Bambura return dev_err_probe(dev, PTR_ERR(ctx->supply), 125*ac488854SAnton Bambura "Failed to get power regulator\n"); 126*ac488854SAnton Bambura 127*ac488854SAnton Bambura ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); 128*ac488854SAnton Bambura if (IS_ERR(ctx->reset_gpio)) 129*ac488854SAnton Bambura return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 130*ac488854SAnton Bambura "Failed to get reset-gpios\n"); 131*ac488854SAnton Bambura 132*ac488854SAnton Bambura ctx->dsi = dsi; 133*ac488854SAnton Bambura mipi_dsi_set_drvdata(dsi, ctx); 134*ac488854SAnton Bambura 135*ac488854SAnton Bambura dsi->lanes = 4; 136*ac488854SAnton Bambura dsi->format = MIPI_DSI_FMT_RGB888; 137*ac488854SAnton Bambura dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM; 138*ac488854SAnton Bambura 139*ac488854SAnton Bambura ret = drm_panel_of_backlight(&ctx->panel); 140*ac488854SAnton Bambura if (ret) 141*ac488854SAnton Bambura return dev_err_probe(dev, ret, "Failed to get backlight\n"); 142*ac488854SAnton Bambura 143*ac488854SAnton Bambura drm_panel_add(&ctx->panel); 144*ac488854SAnton Bambura 145*ac488854SAnton Bambura ret = devm_mipi_dsi_attach(dev, dsi); 146*ac488854SAnton Bambura if (ret < 0) { 147*ac488854SAnton Bambura drm_panel_remove(&ctx->panel); 148*ac488854SAnton Bambura return dev_err_probe(dev, ret, "Failed to attach to DSI host\n"); 149*ac488854SAnton Bambura } 150*ac488854SAnton Bambura 151*ac488854SAnton Bambura return 0; 152*ac488854SAnton Bambura } 153*ac488854SAnton Bambura 154*ac488854SAnton Bambura static void samsung_ltl106hl02_remove(struct mipi_dsi_device *dsi) 155*ac488854SAnton Bambura { 156*ac488854SAnton Bambura struct samsung_ltl106hl02 *ctx = mipi_dsi_get_drvdata(dsi); 157*ac488854SAnton Bambura 158*ac488854SAnton Bambura drm_panel_remove(&ctx->panel); 159*ac488854SAnton Bambura } 160*ac488854SAnton Bambura 161*ac488854SAnton Bambura static const struct of_device_id samsung_ltl106hl02_of_match[] = { 162*ac488854SAnton Bambura { .compatible = "samsung,ltl106hl02-001" }, 163*ac488854SAnton Bambura { /* sentinel */ } 164*ac488854SAnton Bambura }; 165*ac488854SAnton Bambura MODULE_DEVICE_TABLE(of, samsung_ltl106hl02_of_match); 166*ac488854SAnton Bambura 167*ac488854SAnton Bambura static struct mipi_dsi_driver samsung_ltl106hl02_driver = { 168*ac488854SAnton Bambura .driver = { 169*ac488854SAnton Bambura .name = "panel-samsung-ltl106hl02", 170*ac488854SAnton Bambura .of_match_table = samsung_ltl106hl02_of_match, 171*ac488854SAnton Bambura }, 172*ac488854SAnton Bambura .probe = samsung_ltl106hl02_probe, 173*ac488854SAnton Bambura .remove = samsung_ltl106hl02_remove, 174*ac488854SAnton Bambura }; 175*ac488854SAnton Bambura module_mipi_dsi_driver(samsung_ltl106hl02_driver); 176*ac488854SAnton Bambura 177*ac488854SAnton Bambura MODULE_AUTHOR("Anton Bambura <jenneron@protonmail.com>"); 178*ac488854SAnton Bambura MODULE_DESCRIPTION("DRM driver for Samsung LTL106HL02 video mode DSI panel"); 179*ac488854SAnton Bambura MODULE_LICENSE("GPL"); 180