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