1195534Sscottl// SPDX-License-Identifier: GPL-2.0 2195534Sscottl/* 3195534Sscottl * Copyright (C) 2016 InforceComputing 4195534Sscottl * Copyright (C) 2016 Linaro Ltd 5195534Sscottl * Copyright (C) 2023 BayLibre, SAS 6195534Sscottl * 7195534Sscottl * Authors: 8195534Sscottl * - Vinay Simha BN <simhavcs@gmail.com> 9195534Sscottl * - Sumit Semwal <sumit.semwal@linaro.org> 10195534Sscottl * - Guillaume La Roque <glaroque@baylibre.com> 11195534Sscottl * 12195534Sscottl */ 13195534Sscottl 14195534Sscottl#include <linux/backlight.h> 15195534Sscottl#include <linux/delay.h> 16195534Sscottl#include <linux/gpio/consumer.h> 17195534Sscottl#include <linux/module.h> 18195534Sscottl#include <linux/of.h> 19195534Sscottl#include <linux/regulator/consumer.h> 20195534Sscottl 21195534Sscottl#include <video/mipi_display.h> 22195534Sscottl 23195534Sscottl#include <drm/drm_mipi_dsi.h> 24195534Sscottl#include <drm/drm_modes.h> 25195534Sscottl#include <drm/drm_panel.h> 26195534Sscottl 27195534Sscottl#define DSI_REG_MCAP 0xB0 28195534Sscottl#define DSI_REG_IS 0xB3 /* Interface Setting */ 29195534Sscottl#define DSI_REG_IIS 0xB4 /* Interface ID Setting */ 30195534Sscottl#define DSI_REG_CTRL 0xB6 31195534Sscottl 32195534Sscottlenum { 33195534Sscottl IOVCC = 0, 34195534Sscottl POWER = 1 35195534Sscottl}; 36195534Sscottl 37195534Sscottlstruct stk_panel { 38195534Sscottl const struct drm_display_mode *mode; 39195534Sscottl struct backlight_device *backlight; 40195534Sscottl struct drm_panel base; 41195534Sscottl struct gpio_desc *enable_gpio; /* Power IC supply enable */ 42195534Sscottl struct gpio_desc *reset_gpio; /* External reset */ 43195534Sscottl struct mipi_dsi_device *dsi; 44195534Sscottl struct regulator_bulk_data supplies[2]; 45195534Sscottl}; 46195534Sscottl 47195534Sscottlstatic inline struct stk_panel *to_stk_panel(struct drm_panel *panel) 48195534Sscottl{ 49195534Sscottl return container_of(panel, struct stk_panel, base); 50195534Sscottl} 51195534Sscottl 52195534Sscottlstatic int stk_panel_init(struct stk_panel *stk) 53195534Sscottl{ 54195534Sscottl struct mipi_dsi_device *dsi = stk->dsi; 55195534Sscottl struct device *dev = &stk->dsi->dev; 56195534Sscottl int ret; 57195534Sscottl 58195534Sscottl ret = mipi_dsi_dcs_soft_reset(dsi); 59195534Sscottl if (ret < 0) { 60195534Sscottl dev_err(dev, "failed to mipi_dsi_dcs_soft_reset: %d\n", ret); 61195534Sscottl return ret; 62195534Sscottl } 63195534Sscottl mdelay(5); 64195534Sscottl 65195534Sscottl ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 66195534Sscottl if (ret < 0) { 67195534Sscottl dev_err(dev, "failed to set exit sleep mode: %d\n", ret); 68195534Sscottl return ret; 69195534Sscottl } 70195534Sscottl msleep(120); 71198849Smav 72198849Smav mipi_dsi_generic_write_seq(dsi, DSI_REG_MCAP, 0x04); 73198849Smav 74198849Smav /* Interface setting, video mode */ 75220616Smav mipi_dsi_generic_write_seq(dsi, DSI_REG_IS, 0x14, 0x08, 0x00, 0x22, 0x00); 76220616Smav mipi_dsi_generic_write_seq(dsi, DSI_REG_IIS, 0x0C, 0x00); 77198849Smav mipi_dsi_generic_write_seq(dsi, DSI_REG_CTRL, 0x3A, 0xD3); 78198849Smav 79198849Smav ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x77); 80201139Smav if (ret < 0) { 81201139Smav dev_err(dev, "failed to write display brightness: %d\n", ret); 82201139Smav return ret; 83201139Smav } 84201139Smav 85198849Smav mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 86198849Smav MIPI_DCS_WRITE_MEMORY_START); 87198849Smav 88198849Smav ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77); 89198849Smav if (ret < 0) { 90198849Smav dev_err(dev, "failed to set pixel format: %d\n", ret); 91198849Smav return ret; 92198849Smav } 93198849Smav 94198849Smav ret = mipi_dsi_dcs_set_column_address(dsi, 0, stk->mode->hdisplay - 1); 95198849Smav if (ret < 0) { 96198849Smav dev_err(dev, "failed to set column address: %d\n", ret); 97198849Smav return ret; 98198849Smav } 99198849Smav 100198849Smav ret = mipi_dsi_dcs_set_page_address(dsi, 0, stk->mode->vdisplay - 1); 101198849Smav if (ret < 0) { 102198849Smav dev_err(dev, "failed to set page address: %d\n", ret); 103200008Smav return ret; 104200008Smav } 105198849Smav 106198849Smav return 0; 107198849Smav} 108198849Smav 109198849Smavstatic int stk_panel_on(struct stk_panel *stk) 110198849Smav{ 111235897Smav struct mipi_dsi_device *dsi = stk->dsi; 112235897Smav struct device *dev = &stk->dsi->dev; 113235897Smav int ret; 114235897Smav 115235897Smav ret = mipi_dsi_dcs_set_display_on(dsi); 116235897Smav if (ret < 0) 117235897Smav dev_err(dev, "failed to set display on: %d\n", ret); 118235897Smav 119235897Smav mdelay(20); 120235897Smav 121198849Smav return ret; 122198849Smav} 123198849Smav 124198849Smavstatic void stk_panel_off(struct stk_panel *stk) 125198849Smav{ 126198849Smav struct mipi_dsi_device *dsi = stk->dsi; 127198849Smav struct device *dev = &stk->dsi->dev; 128198849Smav int ret; 129198849Smav 130198849Smav dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 131198849Smav 132198849Smav ret = mipi_dsi_dcs_set_display_off(dsi); 133198849Smav if (ret < 0) 134198849Smav dev_err(dev, "failed to set display off: %d\n", ret); 135198849Smav 136198849Smav ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 137198849Smav if (ret < 0) 138198849Smav dev_err(dev, "failed to enter sleep mode: %d\n", ret); 139200008Smav 140198849Smav msleep(100); 141198849Smav} 142198849Smav 143198849Smavstatic int stk_panel_unprepare(struct drm_panel *panel) 144198849Smav{ 145198849Smav struct stk_panel *stk = to_stk_panel(panel); 146198849Smav 147198849Smav stk_panel_off(stk); 148198849Smav regulator_bulk_disable(ARRAY_SIZE(stk->supplies), stk->supplies); 149198849Smav gpiod_set_value(stk->reset_gpio, 0); 150198849Smav gpiod_set_value(stk->enable_gpio, 1); 151198849Smav 152198849Smav return 0; 153198849Smav} 154198849Smav 155198849Smavstatic int stk_panel_prepare(struct drm_panel *panel) 156198849Smav{ 157198849Smav struct stk_panel *stk = to_stk_panel(panel); 158198849Smav struct device *dev = &stk->dsi->dev; 159198849Smav int ret; 160198849Smav 161203421Smav gpiod_set_value(stk->reset_gpio, 0); 162203421Smav gpiod_set_value(stk->enable_gpio, 0); 163203421Smav ret = regulator_enable(stk->supplies[IOVCC].consumer); 164220616Smav if (ret < 0) 165220616Smav return ret; 166198849Smav 167198849Smav mdelay(8); 168198849Smav ret = regulator_enable(stk->supplies[POWER].consumer); 169198849Smav if (ret < 0) 170198849Smav goto iovccoff; 171198849Smav 172198849Smav mdelay(20); 173198849Smav gpiod_set_value(stk->enable_gpio, 1); 174238363Sbrueffer mdelay(20); 175238363Sbrueffer gpiod_set_value(stk->reset_gpio, 1); 176198849Smav mdelay(10); 177198849Smav ret = stk_panel_init(stk); 178198849Smav if (ret < 0) { 179198849Smav dev_err(dev, "failed to init panel: %d\n", ret); 180198849Smav goto poweroff; 181198849Smav } 182198849Smav 183198849Smav ret = stk_panel_on(stk); 184198849Smav if (ret < 0) { 185198849Smav dev_err(dev, "failed to set panel on: %d\n", ret); 186198849Smav goto poweroff; 187198849Smav } 188198849Smav 189198849Smav return 0; 190198849Smav 191198849Smavpoweroff: 192198849Smav regulator_disable(stk->supplies[POWER].consumer); 193198849Smaviovccoff: 194198849Smav regulator_disable(stk->supplies[IOVCC].consumer); 195198849Smav gpiod_set_value(stk->reset_gpio, 0); 196198849Smav gpiod_set_value(stk->enable_gpio, 0); 197198849Smav 198198849Smav return ret; 199198849Smav} 200198849Smav 201198849Smavstatic const struct drm_display_mode default_mode = { 202198849Smav .clock = 163204, 203198849Smav .hdisplay = 1200, 204198849Smav .hsync_start = 1200 + 144, 205198849Smav .hsync_end = 1200 + 144 + 16, 206198849Smav .htotal = 1200 + 144 + 16 + 45, 207198849Smav .vdisplay = 1920, 208198849Smav .vsync_start = 1920 + 8, 209198849Smav .vsync_end = 1920 + 8 + 4, 210198849Smav .vtotal = 1920 + 8 + 4 + 4, 211198849Smav .width_mm = 95, 212198849Smav .height_mm = 151, 213198849Smav}; 214198849Smav 215198849Smavstatic int stk_panel_get_modes(struct drm_panel *panel, 216198849Smav struct drm_connector *connector) 217198849Smav{ 218203108Smav struct drm_display_mode *mode; 219198849Smav 220198849Smav mode = drm_mode_duplicate(connector->dev, &default_mode); 221198849Smav if (!mode) { 222198849Smav dev_err(panel->dev, "failed to add mode %ux%ux@%u\n", 223198849Smav default_mode.hdisplay, default_mode.vdisplay, 224198849Smav drm_mode_vrefresh(&default_mode)); 225198849Smav return -ENOMEM; 226198849Smav } 227198849Smav 228198849Smav drm_mode_set_name(mode); 229198849Smav drm_mode_probed_add(connector, mode); 230198849Smav connector->display_info.width_mm = default_mode.width_mm; 231198849Smav connector->display_info.height_mm = default_mode.height_mm; 232203108Smav return 1; 233198849Smav} 234198849Smav 235198849Smavstatic int dsi_dcs_bl_get_brightness(struct backlight_device *bl) 236198849Smav{ 237198849Smav struct mipi_dsi_device *dsi = bl_get_data(bl); 238198849Smav int ret; 239198849Smav u16 brightness; 240198849Smav 241198849Smav dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 242198849Smav ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness); 243203108Smav if (ret < 0) 244198849Smav return ret; 245198849Smav 246198849Smav dsi->mode_flags |= MIPI_DSI_MODE_LPM; 247198849Smav return brightness & 0xff; 248198849Smav} 249198849Smav 250198849Smavstatic int dsi_dcs_bl_update_status(struct backlight_device *bl) 251198849Smav{ 252198849Smav struct mipi_dsi_device *dsi = bl_get_data(bl); 253198849Smav struct device *dev = &dsi->dev; 254198849Smav int ret; 255198849Smav 256198849Smav dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 257198849Smav ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness); 258198849Smav if (ret < 0) { 259198849Smav dev_err(dev, "failed to set DSI control: %d\n", ret); 260198849Smav return ret; 261198849Smav } 262198849Smav 263198849Smav dsi->mode_flags |= MIPI_DSI_MODE_LPM; 264198849Smav return 0; 265198849Smav} 266198849Smav 267198849Smavstatic const struct backlight_ops dsi_bl_ops = { 268198849Smav .update_status = dsi_dcs_bl_update_status, 269198849Smav .get_brightness = dsi_dcs_bl_get_brightness, 270198849Smav}; 271198849Smav 272195534Sscottlstatic struct backlight_device * 273195534Sscottldrm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi) 274195534Sscottl{ 275195534Sscottl struct device *dev = &dsi->dev; 276195534Sscottl struct backlight_properties props = { 277195534Sscottl .type = BACKLIGHT_RAW, 278195534Sscottl .brightness = 255, 279195534Sscottl .max_brightness = 255, 280195534Sscottl }; 281200218Smav 282200218Smav return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 283223019Smav &dsi_bl_ops, &props); 284200218Smav} 285200218Smav 286195534Sscottlstatic const struct drm_panel_funcs stk_panel_funcs = { 287197541Smav .unprepare = stk_panel_unprepare, 288197541Smav .prepare = stk_panel_prepare, 289197541Smav .get_modes = stk_panel_get_modes, 290195534Sscottl}; 291195534Sscottl 292195534Sscottlstatic const struct of_device_id stk_of_match[] = { 293195534Sscottl { .compatible = "startek,kd070fhfid015", }, 294195534Sscottl { } 295195534Sscottl}; 296195534SscottlMODULE_DEVICE_TABLE(of, stk_of_match); 297195534Sscottl 298195534Sscottlstatic int stk_panel_add(struct stk_panel *stk) 299235897Smav{ 300257049Smav struct device *dev = &stk->dsi->dev; 301257049Smav int ret; 302257049Smav 303257049Smav stk->mode = &default_mode; 304257049Smav 305257049Smav stk->supplies[IOVCC].supply = "iovcc"; 306257049Smav stk->supplies[POWER].supply = "power"; 307257049Smav ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(stk->supplies), stk->supplies); 308257049Smav if (ret) { 309257049Smav dev_err(dev, "regulator_bulk failed\n"); 310257049Smav return ret; 311257049Smav } 312235897Smav 313235897Smav stk->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 314235897Smav if (IS_ERR(stk->reset_gpio)) { 315235897Smav ret = PTR_ERR(stk->reset_gpio); 316235897Smav dev_err(dev, "cannot get reset-gpios %d\n", ret); 317235897Smav return ret; 318235897Smav } 319235897Smav 320235897Smav stk->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 321235897Smav if (IS_ERR(stk->enable_gpio)) { 322235897Smav ret = PTR_ERR(stk->enable_gpio); 323235897Smav dev_err(dev, "cannot get enable-gpio %d\n", ret); 324235897Smav return ret; 325235897Smav } 326257049Smav 327257049Smav stk->backlight = drm_panel_create_dsi_backlight(stk->dsi); 328257049Smav if (IS_ERR(stk->backlight)) { 329257049Smav ret = PTR_ERR(stk->backlight); 330257049Smav dev_err(dev, "failed to register backlight %d\n", ret); 331257049Smav return ret; 332257049Smav } 333257049Smav 334257049Smav drm_panel_init(&stk->base, &stk->dsi->dev, &stk_panel_funcs, 335257049Smav DRM_MODE_CONNECTOR_DSI); 336257049Smav 337257049Smav drm_panel_add(&stk->base); 338198897Smav 339198897Smav return 0; 340198897Smav} 341198897Smav 342198897Smavstatic int stk_panel_probe(struct mipi_dsi_device *dsi) 343198897Smav{ 344198897Smav struct stk_panel *stk; 345198897Smav int ret; 346198897Smav 347198897Smav dsi->lanes = 4; 348198897Smav dsi->format = MIPI_DSI_FMT_RGB888; 349198897Smav dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM); 350198897Smav 351198897Smav stk = devm_kzalloc(&dsi->dev, sizeof(*stk), GFP_KERNEL); 352198897Smav if (!stk) 353198897Smav return -ENOMEM; 354198897Smav 355198897Smav mipi_dsi_set_drvdata(dsi, stk); 356198897Smav 357198897Smav stk->dsi = dsi; 358198897Smav 359198897Smav ret = stk_panel_add(stk); 360198897Smav if (ret < 0) 361198897Smav return ret; 362198897Smav 363198897Smav ret = mipi_dsi_attach(dsi); 364198897Smav if (ret < 0) 365198897Smav drm_panel_remove(&stk->base); 366198897Smav 367198897Smav return 0; 368198897Smav} 369198897Smav 370195534Sscottlstatic void stk_panel_remove(struct mipi_dsi_device *dsi) 371196659Smav{ 372195534Sscottl struct stk_panel *stk = mipi_dsi_get_drvdata(dsi); 373195534Sscottl int err; 374195534Sscottl 375195534Sscottl err = mipi_dsi_detach(dsi); 376200008Smav if (err < 0) 377200008Smav dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", 378200008Smav err); 379200008Smav 380200008Smav drm_panel_remove(&stk->base); 381195534Sscottl} 382195534Sscottl 383195534Sscottlstatic struct mipi_dsi_driver stk_panel_driver = { 384195534Sscottl .driver = { 385195534Sscottl .name = "panel-startek-kd070fhfid015", 386238393Sbrueffer .of_match_table = stk_of_match, 387195534Sscottl }, 388195534Sscottl .probe = stk_panel_probe, 389195534Sscottl .remove = stk_panel_remove, 390195534Sscottl}; 391195534Sscottlmodule_mipi_dsi_driver(stk_panel_driver); 392195534Sscottl 393195534SscottlMODULE_AUTHOR("Guillaume La Roque <glaroque@baylibre.com>"); 394248695SmavMODULE_DESCRIPTION("STARTEK KD070FHFID015"); 395195534SscottlMODULE_LICENSE("GPL"); 396200008Smav