1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (C) 2016 InforceComputing 4 * Copyright (C) 2016 Linaro Ltd 5 * Copyright (C) 2023 BayLibre, SAS 6 * 7 * Authors: 8 * - Vinay Simha BN <simhavcs@gmail.com> 9 * - Sumit Semwal <sumit.semwal@linaro.org> 10 * - Guillaume La Roque <glaroque@baylibre.com> 11 * 12 */ 13 14 #include <linux/backlight.h> 15 #include <linux/delay.h> 16 #include <linux/gpio/consumer.h> 17 #include <linux/module.h> 18 #include <linux/of.h> 19 #include <linux/regulator/consumer.h> 20 21 #include <video/mipi_display.h> 22 23 #include <drm/drm_mipi_dsi.h> 24 #include <drm/drm_modes.h> 25 #include <drm/drm_panel.h> 26 27 #define DSI_REG_MCAP 0xB0 28 #define DSI_REG_IS 0xB3 /* Interface Setting */ 29 #define DSI_REG_IIS 0xB4 /* Interface ID Setting */ 30 #define DSI_REG_CTRL 0xB6 31 32 enum { 33 IOVCC = 0, 34 POWER = 1 35 }; 36 37 struct stk_panel { 38 bool prepared; 39 const struct drm_display_mode *mode; 40 struct backlight_device *backlight; 41 struct drm_panel base; 42 struct gpio_desc *enable_gpio; /* Power IC supply enable */ 43 struct gpio_desc *reset_gpio; /* External reset */ 44 struct mipi_dsi_device *dsi; 45 struct regulator_bulk_data supplies[2]; 46 }; 47 48 static inline struct stk_panel *to_stk_panel(struct drm_panel *panel) 49 { 50 return container_of(panel, struct stk_panel, base); 51 } 52 53 static int stk_panel_init(struct stk_panel *stk) 54 { 55 struct mipi_dsi_device *dsi = stk->dsi; 56 struct device *dev = &stk->dsi->dev; 57 int ret; 58 59 ret = mipi_dsi_dcs_soft_reset(dsi); 60 if (ret < 0) { 61 dev_err(dev, "failed to mipi_dsi_dcs_soft_reset: %d\n", ret); 62 return ret; 63 } 64 mdelay(5); 65 66 ret = mipi_dsi_dcs_exit_sleep_mode(dsi); 67 if (ret < 0) { 68 dev_err(dev, "failed to set exit sleep mode: %d\n", ret); 69 return ret; 70 } 71 msleep(120); 72 73 mipi_dsi_generic_write_seq(dsi, DSI_REG_MCAP, 0x04); 74 75 /* Interface setting, video mode */ 76 mipi_dsi_generic_write_seq(dsi, DSI_REG_IS, 0x14, 0x08, 0x00, 0x22, 0x00); 77 mipi_dsi_generic_write_seq(dsi, DSI_REG_IIS, 0x0C, 0x00); 78 mipi_dsi_generic_write_seq(dsi, DSI_REG_CTRL, 0x3A, 0xD3); 79 80 ret = mipi_dsi_dcs_set_display_brightness(dsi, 0x77); 81 if (ret < 0) { 82 dev_err(dev, "failed to write display brightness: %d\n", ret); 83 return ret; 84 } 85 86 mipi_dsi_dcs_write_seq(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY, 87 MIPI_DCS_WRITE_MEMORY_START); 88 89 ret = mipi_dsi_dcs_set_pixel_format(dsi, 0x77); 90 if (ret < 0) { 91 dev_err(dev, "failed to set pixel format: %d\n", ret); 92 return ret; 93 } 94 95 ret = mipi_dsi_dcs_set_column_address(dsi, 0, stk->mode->hdisplay - 1); 96 if (ret < 0) { 97 dev_err(dev, "failed to set column address: %d\n", ret); 98 return ret; 99 } 100 101 ret = mipi_dsi_dcs_set_page_address(dsi, 0, stk->mode->vdisplay - 1); 102 if (ret < 0) { 103 dev_err(dev, "failed to set page address: %d\n", ret); 104 return ret; 105 } 106 107 return 0; 108 } 109 110 static int stk_panel_on(struct stk_panel *stk) 111 { 112 struct mipi_dsi_device *dsi = stk->dsi; 113 struct device *dev = &stk->dsi->dev; 114 int ret; 115 116 ret = mipi_dsi_dcs_set_display_on(dsi); 117 if (ret < 0) 118 dev_err(dev, "failed to set display on: %d\n", ret); 119 120 mdelay(20); 121 122 return ret; 123 } 124 125 static void stk_panel_off(struct stk_panel *stk) 126 { 127 struct mipi_dsi_device *dsi = stk->dsi; 128 struct device *dev = &stk->dsi->dev; 129 int ret; 130 131 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 132 133 ret = mipi_dsi_dcs_set_display_off(dsi); 134 if (ret < 0) 135 dev_err(dev, "failed to set display off: %d\n", ret); 136 137 ret = mipi_dsi_dcs_enter_sleep_mode(dsi); 138 if (ret < 0) 139 dev_err(dev, "failed to enter sleep mode: %d\n", ret); 140 141 msleep(100); 142 } 143 144 static int stk_panel_unprepare(struct drm_panel *panel) 145 { 146 struct stk_panel *stk = to_stk_panel(panel); 147 148 if (!stk->prepared) 149 return 0; 150 151 stk_panel_off(stk); 152 regulator_bulk_disable(ARRAY_SIZE(stk->supplies), stk->supplies); 153 gpiod_set_value(stk->reset_gpio, 0); 154 gpiod_set_value(stk->enable_gpio, 1); 155 156 stk->prepared = false; 157 158 return 0; 159 } 160 161 static int stk_panel_prepare(struct drm_panel *panel) 162 { 163 struct stk_panel *stk = to_stk_panel(panel); 164 struct device *dev = &stk->dsi->dev; 165 int ret; 166 167 if (stk->prepared) 168 return 0; 169 170 gpiod_set_value(stk->reset_gpio, 0); 171 gpiod_set_value(stk->enable_gpio, 0); 172 ret = regulator_enable(stk->supplies[IOVCC].consumer); 173 if (ret < 0) 174 return ret; 175 176 mdelay(8); 177 ret = regulator_enable(stk->supplies[POWER].consumer); 178 if (ret < 0) 179 goto iovccoff; 180 181 mdelay(20); 182 gpiod_set_value(stk->enable_gpio, 1); 183 mdelay(20); 184 gpiod_set_value(stk->reset_gpio, 1); 185 mdelay(10); 186 ret = stk_panel_init(stk); 187 if (ret < 0) { 188 dev_err(dev, "failed to init panel: %d\n", ret); 189 goto poweroff; 190 } 191 192 ret = stk_panel_on(stk); 193 if (ret < 0) { 194 dev_err(dev, "failed to set panel on: %d\n", ret); 195 goto poweroff; 196 } 197 198 stk->prepared = true; 199 200 return 0; 201 202 poweroff: 203 regulator_disable(stk->supplies[POWER].consumer); 204 iovccoff: 205 regulator_disable(stk->supplies[IOVCC].consumer); 206 gpiod_set_value(stk->reset_gpio, 0); 207 gpiod_set_value(stk->enable_gpio, 0); 208 209 return ret; 210 } 211 212 static const struct drm_display_mode default_mode = { 213 .clock = 163204, 214 .hdisplay = 1200, 215 .hsync_start = 1200 + 144, 216 .hsync_end = 1200 + 144 + 16, 217 .htotal = 1200 + 144 + 16 + 45, 218 .vdisplay = 1920, 219 .vsync_start = 1920 + 8, 220 .vsync_end = 1920 + 8 + 4, 221 .vtotal = 1920 + 8 + 4 + 4, 222 .width_mm = 95, 223 .height_mm = 151, 224 }; 225 226 static int stk_panel_get_modes(struct drm_panel *panel, 227 struct drm_connector *connector) 228 { 229 struct drm_display_mode *mode; 230 231 mode = drm_mode_duplicate(connector->dev, &default_mode); 232 if (!mode) { 233 dev_err(panel->dev, "failed to add mode %ux%ux@%u\n", 234 default_mode.hdisplay, default_mode.vdisplay, 235 drm_mode_vrefresh(&default_mode)); 236 return -ENOMEM; 237 } 238 239 drm_mode_set_name(mode); 240 drm_mode_probed_add(connector, mode); 241 connector->display_info.width_mm = default_mode.width_mm; 242 connector->display_info.height_mm = default_mode.height_mm; 243 return 1; 244 } 245 246 static int dsi_dcs_bl_get_brightness(struct backlight_device *bl) 247 { 248 struct mipi_dsi_device *dsi = bl_get_data(bl); 249 int ret; 250 u16 brightness; 251 252 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 253 ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness); 254 if (ret < 0) 255 return ret; 256 257 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 258 return brightness & 0xff; 259 } 260 261 static int dsi_dcs_bl_update_status(struct backlight_device *bl) 262 { 263 struct mipi_dsi_device *dsi = bl_get_data(bl); 264 struct device *dev = &dsi->dev; 265 int ret; 266 267 dsi->mode_flags &= ~MIPI_DSI_MODE_LPM; 268 ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness); 269 if (ret < 0) { 270 dev_err(dev, "failed to set DSI control: %d\n", ret); 271 return ret; 272 } 273 274 dsi->mode_flags |= MIPI_DSI_MODE_LPM; 275 return 0; 276 } 277 278 static const struct backlight_ops dsi_bl_ops = { 279 .update_status = dsi_dcs_bl_update_status, 280 .get_brightness = dsi_dcs_bl_get_brightness, 281 }; 282 283 static struct backlight_device * 284 drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi) 285 { 286 struct device *dev = &dsi->dev; 287 struct backlight_properties props = { 288 .type = BACKLIGHT_RAW, 289 .brightness = 255, 290 .max_brightness = 255, 291 }; 292 293 return devm_backlight_device_register(dev, dev_name(dev), dev, dsi, 294 &dsi_bl_ops, &props); 295 } 296 297 static const struct drm_panel_funcs stk_panel_funcs = { 298 .unprepare = stk_panel_unprepare, 299 .prepare = stk_panel_prepare, 300 .get_modes = stk_panel_get_modes, 301 }; 302 303 static const struct of_device_id stk_of_match[] = { 304 { .compatible = "startek,kd070fhfid015", }, 305 { } 306 }; 307 MODULE_DEVICE_TABLE(of, stk_of_match); 308 309 static int stk_panel_add(struct stk_panel *stk) 310 { 311 struct device *dev = &stk->dsi->dev; 312 int ret; 313 314 stk->mode = &default_mode; 315 316 stk->supplies[IOVCC].supply = "iovcc"; 317 stk->supplies[POWER].supply = "power"; 318 ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(stk->supplies), stk->supplies); 319 if (ret) { 320 dev_err(dev, "regulator_bulk failed\n"); 321 return ret; 322 } 323 324 stk->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); 325 if (IS_ERR(stk->reset_gpio)) { 326 ret = PTR_ERR(stk->reset_gpio); 327 dev_err(dev, "cannot get reset-gpios %d\n", ret); 328 return ret; 329 } 330 331 stk->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW); 332 if (IS_ERR(stk->enable_gpio)) { 333 ret = PTR_ERR(stk->enable_gpio); 334 dev_err(dev, "cannot get enable-gpio %d\n", ret); 335 return ret; 336 } 337 338 stk->backlight = drm_panel_create_dsi_backlight(stk->dsi); 339 if (IS_ERR(stk->backlight)) { 340 ret = PTR_ERR(stk->backlight); 341 dev_err(dev, "failed to register backlight %d\n", ret); 342 return ret; 343 } 344 345 drm_panel_init(&stk->base, &stk->dsi->dev, &stk_panel_funcs, 346 DRM_MODE_CONNECTOR_DSI); 347 348 drm_panel_add(&stk->base); 349 350 return 0; 351 } 352 353 static int stk_panel_probe(struct mipi_dsi_device *dsi) 354 { 355 struct stk_panel *stk; 356 int ret; 357 358 dsi->lanes = 4; 359 dsi->format = MIPI_DSI_FMT_RGB888; 360 dsi->mode_flags = (MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_LPM); 361 362 stk = devm_kzalloc(&dsi->dev, sizeof(*stk), GFP_KERNEL); 363 if (!stk) 364 return -ENOMEM; 365 366 mipi_dsi_set_drvdata(dsi, stk); 367 368 stk->dsi = dsi; 369 370 ret = stk_panel_add(stk); 371 if (ret < 0) 372 return ret; 373 374 ret = mipi_dsi_attach(dsi); 375 if (ret < 0) 376 drm_panel_remove(&stk->base); 377 378 return 0; 379 } 380 381 static void stk_panel_remove(struct mipi_dsi_device *dsi) 382 { 383 struct stk_panel *stk = mipi_dsi_get_drvdata(dsi); 384 int err; 385 386 err = mipi_dsi_detach(dsi); 387 if (err < 0) 388 dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", 389 err); 390 391 drm_panel_remove(&stk->base); 392 } 393 394 static struct mipi_dsi_driver stk_panel_driver = { 395 .driver = { 396 .name = "panel-startek-kd070fhfid015", 397 .of_match_table = stk_of_match, 398 }, 399 .probe = stk_panel_probe, 400 .remove = stk_panel_remove, 401 }; 402 module_mipi_dsi_driver(stk_panel_driver); 403 404 MODULE_AUTHOR("Guillaume La Roque <glaroque@baylibre.com>"); 405 MODULE_DESCRIPTION("STARTEK KD070FHFID015"); 406 MODULE_LICENSE("GPL"); 407