1255376Sdes// SPDX-License-Identifier: GPL-2.0-only 2255376Sdes/* 3255376Sdes * Copyright (c) 2022 Joel Selvaraj <jo@jsfamily.in> 4255376Sdes * Generated with linux-mdss-dsi-panel-driver-generator from vendor device tree: 5255376Sdes * Copyright (c) 2013, The Linux Foundation. All rights reserved. 6255376Sdes */ 7255376Sdes 8255376Sdes#include <linux/delay.h> 9255376Sdes#include <linux/gpio/consumer.h> 10255376Sdes#include <linux/regulator/consumer.h> 11255376Sdes#include <linux/module.h> 12255376Sdes#include <linux/of.h> 13255376Sdes 14255376Sdes#include <video/mipi_display.h> 15255376Sdes 16255376Sdes#include <drm/drm_mipi_dsi.h> 17255376Sdes#include <drm/drm_modes.h> 18255376Sdes#include <drm/drm_panel.h> 19255376Sdes 20255376Sdesstatic const char * const regulator_names[] = { 21255376Sdes "vddio", 22255376Sdes "vddpos", 23255376Sdes "vddneg", 24255376Sdes}; 25255376Sdes 26255376Sdesstatic const unsigned long regulator_enable_loads[] = { 27255376Sdes 62000, 28236109Sdes 100000, 29236109Sdes 100000 30236109Sdes}; 31236109Sdes 32236109Sdesstruct ebbg_ft8719 { 33236109Sdes struct drm_panel panel; 34236109Sdes struct mipi_dsi_device *dsi; 35236109Sdes 36236109Sdes struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)]; 37236109Sdes 38236109Sdes struct gpio_desc *reset_gpio; 39236109Sdes}; 40236109Sdes 41236109Sdesstatic inline 42236109Sdesstruct ebbg_ft8719 *to_ebbg_ft8719(struct drm_panel *panel) 43236109Sdes{ 44236109Sdes return container_of(panel, struct ebbg_ft8719, panel); 45236109Sdes} 46236109Sdes 47236109Sdesstatic void ebbg_ft8719_reset(struct ebbg_ft8719 *ctx) 48236109Sdes{ 49236109Sdes gpiod_set_value_cansleep(ctx->reset_gpio, 0); 50236109Sdes usleep_range(4000, 5000); 51236109Sdes gpiod_set_value_cansleep(ctx->reset_gpio, 1); 52236109Sdes usleep_range(1000, 2000); 53236109Sdes gpiod_set_value_cansleep(ctx->reset_gpio, 0); 54236109Sdes usleep_range(15000, 16000); 55236109Sdes} 56236109Sdes 57236109Sdesstatic int ebbg_ft8719_on(struct ebbg_ft8719 *ctx) 58236109Sdes{ 59236109Sdes struct mipi_dsi_device *dsi = ctx->dsi; 60236109Sdes struct device *dev = &dsi->dev; 61236109Sdes int ret; 62236109Sdes 63236109Sdes dsi->mode_flags |= MIPI_DSI_MODE_LPM; 64236109Sdes 65236109Sdes ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x00ff); 66236109Sdes if (ret < 0) { 67236109Sdes dev_err(dev, "Failed to set display brightness: %d\n", ret); 68236109Sdes return ret; 69236109Sdes } 70236109Sdes 71236109Sdes mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x24); 72236109Sdes mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_POWER_SAVE, 0x00); 73236109Sdes 74236109Sdes ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 75236109Sdes if (ret < 0) { 76228692Sdes dev_err(dev, "Failed to exit sleep mode: %d\n", ret); 77228692Sdes return ret; 78228692Sdes } 79228692Sdes msleep(90); 80228692Sdes 81228692Sdes ret = mipi_dsi_dcs_set_display_on(dsi); 82228692Sdes if (ret < 0) { 83228692Sdes dev_err(dev, "Failed to set display on: %d\n", ret); 84228692Sdes return ret; 85228692Sdes } 86228692Sdes 87228692Sdes return 0; 88228692Sdes} 89228692Sdes 90228692Sdesstatic int ebbg_ft8719_off(struct ebbg_ft8719 *ctx) 91228692Sdes{ 92228692Sdes struct mipi_dsi_device *dsi = ctx->dsi; 93228692Sdes struct device *dev = &dsi->dev; 94228692Sdes int ret; 95228692Sdes 96228692Sdes dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 97228692Sdes 98228692Sdes ret = mipi_dsi_dcs_set_display_off(dsi); 99228692Sdes if (ret < 0) { 100228692Sdes dev_err(dev, "Failed to set display off: %d\n", ret); 101228692Sdes return ret; 102174832Sdes } 103147455Sdes usleep_range(10000, 11000); 104174832Sdes 105174832Sdes ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 106174832Sdes if (ret < 0) { 107174832Sdes dev_err(dev, "Failed to enter sleep mode: %d\n", ret); 108174832Sdes return ret; 109174832Sdes } 110174832Sdes msleep(90); 111174832Sdes 112174832Sdes return 0; 113174832Sdes} 114174832Sdes 115174832Sdesstatic int ebbg_ft8719_prepare(struct drm_panel *panel) 116174832Sdes{ 117174832Sdes struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel); 118174832Sdes struct device *dev = &ctx->dsi->dev; 119174832Sdes int ret; 120174832Sdes 121174832Sdes ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 122174832Sdes if (ret < 0) 123174832Sdes return ret; 124174832Sdes 125228692Sdes ebbg_ft8719_reset(ctx); 126174832Sdes 127147455Sdes ret = ebbg_ft8719_on(ctx); 128147455Sdes if (ret < 0) { 129147455Sdes dev_err(dev, "Failed to initialize panel: %d\n", ret); 130147455Sdes gpiod_set_value_cansleep(ctx->reset_gpio, 1); 131147455Sdes return ret; 132147455Sdes } 133147455Sdes 134147455Sdes return 0; 135147455Sdes} 136147455Sdes 137147455Sdesstatic int ebbg_ft8719_unprepare(struct drm_panel *panel) 138141098Sdes{ 139141098Sdes struct ebbg_ft8719 *ctx = to_ebbg_ft8719(panel); 140141098Sdes struct device *dev = &ctx->dsi->dev; 141141098Sdes int ret; 142141098Sdes 143141098Sdes ret = ebbg_ft8719_off(ctx); 144141098Sdes if (ret < 0) 145141098Sdes dev_err(dev, "Failed to un-initialize panel: %d\n", ret); 146141098Sdes 147141098Sdes gpiod_set_value_cansleep(ctx->reset_gpio, 1); 148141098Sdes 149141098Sdes ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies); 150141098Sdes if (ret) 151141098Sdes dev_err(panel->dev, "Failed to disable regulators: %d\n", ret); 152141098Sdes 153141098Sdes return 0; 154141098Sdes} 155141098Sdes 156141098Sdesstatic const struct drm_display_mode ebbg_ft8719_mode = { 157125647Sdes .clock = (1080 + 28 + 4 + 16) * (2246 + 120 + 4 + 12) * 60 / 1000, 158125647Sdes .hdisplay = 1080, 159125647Sdes .hsync_start = 1080 + 28, 160125647Sdes .hsync_end = 1080 + 28 + 4, 161125647Sdes .htotal = 1080 + 28 + 4 + 16, 162125647Sdes .vdisplay = 2246, 163125647Sdes .vsync_start = 2246 + 120, 164125647Sdes .vsync_end = 2246 + 120 + 4, 165125647Sdes .vtotal = 2246 + 120 + 4 + 12, 166117610Sdes .width_mm = 68, 167117610Sdes .height_mm = 141, 168117610Sdes}; 169117610Sdes 170117610Sdesstatic int ebbg_ft8719_get_modes(struct drm_panel *panel, 171117610Sdes struct drm_connector *connector) 172117610Sdes{ 173117610Sdes struct drm_display_mode *mode; 174117610Sdes 175117610Sdes mode = drm_mode_duplicate(connector->dev, &ebbg_ft8719_mode); 176117610Sdes if (!mode) 177117610Sdes return -ENOMEM; 178117610Sdes 179117610Sdes drm_mode_set_name(mode); 180117610Sdes 181117610Sdes mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; 182117610Sdes connector->display_info.width_mm = mode->width_mm; 183117610Sdes connector->display_info.height_mm = mode->height_mm; 184117610Sdes drm_mode_probed_add(connector, mode); 185117610Sdes 186117610Sdes return 1; 187115619Sdes} 188115619Sdes 189115619Sdesstatic const struct drm_panel_funcs ebbg_ft8719_panel_funcs = { 190115619Sdes .prepare = ebbg_ft8719_prepare, 191115619Sdes .unprepare = ebbg_ft8719_unprepare, 192115619Sdes .get_modes = ebbg_ft8719_get_modes, 193115619Sdes}; 194115619Sdes 195115619Sdesstatic int ebbg_ft8719_probe(struct mipi_dsi_device *dsi) 196115619Sdes{ 197115619Sdes struct device *dev = &dsi->dev; 198115619Sdes struct ebbg_ft8719 *ctx; 199115619Sdes int i, ret; 200115619Sdes 201115619Sdes ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); 202115619Sdes if (!ctx) 203115619Sdes return -ENOMEM; 204115619Sdes 205115619Sdes for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) 206114536Sdes ctx->supplies[i].supply = regulator_names[i]; 207114536Sdes 208114536Sdes ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies), 209114536Sdes ctx->supplies); 210114536Sdes if (ret < 0) 211114536Sdes return dev_err_probe(dev, ret, "Failed to get regulators\n"); 212114536Sdes 213114536Sdes for (i = 0; i < ARRAY_SIZE(ctx->supplies); i++) { 214114536Sdes ret = regulator_set_load(ctx->supplies[i].consumer, 215114536Sdes regulator_enable_loads[i]); 216114536Sdes if (ret) 217114536Sdes return dev_err_probe(dev, ret, 218114536Sdes "Failed to set regulator load\n"); 219114536Sdes } 220114536Sdes 221114536Sdes ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 222114536Sdes if (IS_ERR(ctx->reset_gpio)) 223108794Sdes return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), 224108794Sdes "Failed to get reset-gpios\n"); 225108794Sdes 226108794Sdes ctx->dsi = dsi; 227108794Sdes mipi_dsi_set_drvdata(dsi, ctx); 228108794Sdes 229108794Sdes dsi->lanes = 4; 230108794Sdes dsi->format = MIPI_DSI_FMT_RGB888; 231107937Sdes dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | 232107937Sdes MIPI_DSI_CLOCK_NON_CONTINUOUS; 233107937Sdes 234107937Sdes drm_panel_init(&ctx->panel, dev, &ebbg_ft8719_panel_funcs, 235107937Sdes DRM_MODE_CONNECTOR_DSI); 236107937Sdes 237107937Sdes ret = drm_panel_of_backlight(&ctx->panel); 238107937Sdes if (ret) 239107937Sdes return dev_err_probe(dev, ret, "Failed to get backlight\n"); 240107937Sdes 241107937Sdes drm_panel_add(&ctx->panel); 242107937Sdes 243107937Sdes ret = mipi_dsi_attach(dsi); 244107937Sdes if (ret < 0) { 245107937Sdes dev_err(dev, "Failed to attach to DSI host: %d\n", ret); 24691094Sdes drm_panel_remove(&ctx->panel); 24799158Sdes return ret; 24899158Sdes } 24999158Sdes 25099158Sdes return 0; 25199158Sdes} 25299158Sdes 25399158Sdesstatic void ebbg_ft8719_remove(struct mipi_dsi_device *dsi) 254107937Sdes{ 25599158Sdes struct ebbg_ft8719 *ctx = mipi_dsi_get_drvdata(dsi); 25699158Sdes int ret; 25799158Sdes 25899158Sdes ret = mipi_dsi_detach(dsi); 25999158Sdes if (ret < 0) 26099158Sdes dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret); 26199158Sdes 26299158Sdes drm_panel_remove(&ctx->panel); 26399158Sdes} 26499158Sdes 26599158Sdesstatic const struct of_device_id ebbg_ft8719_of_match[] = { 26699158Sdes { .compatible = "ebbg,ft8719" }, 26799158Sdes { /* sentinel */ } 26897241Sdes}; 26997241SdesMODULE_DEVICE_TABLE(of, ebbg_ft8719_of_match); 27097241Sdes 27197241Sdesstatic struct mipi_dsi_driver ebbg_ft8719_driver = { 27297241Sdes .probe = ebbg_ft8719_probe, 27397241Sdes .remove = ebbg_ft8719_remove, 27497241Sdes .driver = { 27597241Sdes .name = "panel-ebbg-ft8719", 27697241Sdes .of_match_table = ebbg_ft8719_of_match, 27797241Sdes }, 27895908Sdes}; 27995908Sdesmodule_mipi_dsi_driver(ebbg_ft8719_driver); 28095908Sdes 28195908SdesMODULE_AUTHOR("Joel Selvaraj <jo@jsfamily.in>"); 28295908SdesMODULE_DESCRIPTION("DRM driver for EBBG FT8719 video dsi panel"); 28395908SdesMODULE_LICENSE("GPL v2"); 28495908Sdes