1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Novatek NT39016 TFT LCD panel driver 4 * 5 * Copyright (C) 2017, Maarten ter Huurne <maarten@treewalker.org> 6 * Copyright (C) 2019, Paul Cercueil <paul@crapouillou.net> 7 */ 8 9 #include <linux/backlight.h> 10 #include <linux/delay.h> 11 #include <linux/device.h> 12 #include <linux/gpio/consumer.h> 13 #include <linux/media-bus-format.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_device.h> 17 #include <linux/regmap.h> 18 #include <linux/regulator/consumer.h> 19 #include <linux/spi/spi.h> 20 21 #include <drm/drm_modes.h> 22 #include <drm/drm_panel.h> 23 24 enum nt39016_regs { 25 NT39016_REG_SYSTEM, 26 NT39016_REG_TIMING, 27 NT39016_REG_OP, 28 NT39016_REG_DATA_IN, 29 NT39016_REG_SRC_TIMING_DELAY, 30 NT39016_REG_GATE_TIMING_DELAY, 31 NT39016_REG_RESERVED, 32 NT39016_REG_INITIAL_FUNC, 33 NT39016_REG_CONTRAST, 34 NT39016_REG_BRIGHTNESS, 35 NT39016_REG_HUE_SATURATION, 36 NT39016_REG_RB_SUBCONTRAST, 37 NT39016_REG_R_SUBBRIGHTNESS, 38 NT39016_REG_B_SUBBRIGHTNESS, 39 NT39016_REG_VCOMDC, 40 NT39016_REG_VCOMAC, 41 NT39016_REG_VGAM2, 42 NT39016_REG_VGAM34, 43 NT39016_REG_VGAM56, 44 NT39016_REG_VCOMDC_TRIM = 0x1e, 45 NT39016_REG_DISPLAY_MODE = 0x20, 46 }; 47 48 #define NT39016_SYSTEM_RESET_N BIT(0) 49 #define NT39016_SYSTEM_STANDBY BIT(1) 50 51 struct nt39016_panel_info { 52 const struct drm_display_mode *display_modes; 53 unsigned int num_modes; 54 u16 width_mm, height_mm; 55 u32 bus_format, bus_flags; 56 }; 57 58 struct nt39016 { 59 struct drm_panel drm_panel; 60 struct device *dev; 61 struct regmap *map; 62 struct regulator *supply; 63 const struct nt39016_panel_info *panel_info; 64 65 struct gpio_desc *reset_gpio; 66 67 struct backlight_device *backlight; 68 }; 69 70 static inline struct nt39016 *to_nt39016(struct drm_panel *panel) 71 { 72 return container_of(panel, struct nt39016, drm_panel); 73 } 74 75 #define RV(REG, VAL) { .reg = (REG), .def = (VAL), .delay_us = 2 } 76 static const struct reg_sequence nt39016_panel_regs[] = { 77 RV(NT39016_REG_SYSTEM, 0x00), 78 RV(NT39016_REG_TIMING, 0x00), 79 RV(NT39016_REG_OP, 0x03), 80 RV(NT39016_REG_DATA_IN, 0xCC), 81 RV(NT39016_REG_SRC_TIMING_DELAY, 0x46), 82 RV(NT39016_REG_GATE_TIMING_DELAY, 0x05), 83 RV(NT39016_REG_RESERVED, 0x00), 84 RV(NT39016_REG_INITIAL_FUNC, 0x00), 85 RV(NT39016_REG_CONTRAST, 0x08), 86 RV(NT39016_REG_BRIGHTNESS, 0x40), 87 RV(NT39016_REG_HUE_SATURATION, 0x88), 88 RV(NT39016_REG_RB_SUBCONTRAST, 0x88), 89 RV(NT39016_REG_R_SUBBRIGHTNESS, 0x20), 90 RV(NT39016_REG_B_SUBBRIGHTNESS, 0x20), 91 RV(NT39016_REG_VCOMDC, 0x67), 92 RV(NT39016_REG_VCOMAC, 0xA4), 93 RV(NT39016_REG_VGAM2, 0x04), 94 RV(NT39016_REG_VGAM34, 0x24), 95 RV(NT39016_REG_VGAM56, 0x24), 96 RV(NT39016_REG_DISPLAY_MODE, 0x00), 97 }; 98 99 #undef RV 100 101 static const struct regmap_range nt39016_regmap_no_ranges[] = { 102 regmap_reg_range(0x13, 0x1D), 103 regmap_reg_range(0x1F, 0x1F), 104 }; 105 106 static const struct regmap_access_table nt39016_regmap_access_table = { 107 .no_ranges = nt39016_regmap_no_ranges, 108 .n_no_ranges = ARRAY_SIZE(nt39016_regmap_no_ranges), 109 }; 110 111 static const struct regmap_config nt39016_regmap_config = { 112 .reg_bits = 6, 113 .pad_bits = 2, 114 .val_bits = 8, 115 116 .max_register = NT39016_REG_DISPLAY_MODE, 117 .wr_table = &nt39016_regmap_access_table, 118 .write_flag_mask = 0x02, 119 120 .cache_type = REGCACHE_FLAT, 121 }; 122 123 static int nt39016_prepare(struct drm_panel *drm_panel) 124 { 125 struct nt39016 *panel = to_nt39016(drm_panel); 126 int err; 127 128 err = regulator_enable(panel->supply); 129 if (err) { 130 dev_err(panel->dev, "Failed to enable power supply: %d", err); 131 return err; 132 } 133 134 /* 135 * Reset the NT39016. 136 * The documentation says the reset pulse should be at least 40 us to 137 * pass the glitch filter, but when testing I see some resets fail and 138 * some succeed when using a 70 us delay, so we use 100 us instead. 139 */ 140 gpiod_set_value_cansleep(panel->reset_gpio, 1); 141 usleep_range(100, 1000); 142 gpiod_set_value_cansleep(panel->reset_gpio, 0); 143 udelay(2); 144 145 /* Init all registers. */ 146 err = regmap_multi_reg_write(panel->map, nt39016_panel_regs, 147 ARRAY_SIZE(nt39016_panel_regs)); 148 if (err) { 149 dev_err(panel->dev, "Failed to init registers: %d", err); 150 goto err_disable_regulator; 151 } 152 153 return 0; 154 155 err_disable_regulator: 156 regulator_disable(panel->supply); 157 return err; 158 } 159 160 static int nt39016_unprepare(struct drm_panel *drm_panel) 161 { 162 struct nt39016 *panel = to_nt39016(drm_panel); 163 164 gpiod_set_value_cansleep(panel->reset_gpio, 1); 165 166 regulator_disable(panel->supply); 167 168 return 0; 169 } 170 171 static int nt39016_enable(struct drm_panel *drm_panel) 172 { 173 struct nt39016 *panel = to_nt39016(drm_panel); 174 int ret; 175 176 ret = regmap_write(panel->map, NT39016_REG_SYSTEM, 177 NT39016_SYSTEM_RESET_N | NT39016_SYSTEM_STANDBY); 178 if (ret) { 179 dev_err(panel->dev, "Unable to enable panel: %d", ret); 180 return ret; 181 } 182 183 if (panel->backlight) { 184 /* Wait for the picture to be ready before enabling backlight */ 185 msleep(150); 186 187 ret = backlight_enable(panel->backlight); 188 } 189 190 return ret; 191 } 192 193 static int nt39016_disable(struct drm_panel *drm_panel) 194 { 195 struct nt39016 *panel = to_nt39016(drm_panel); 196 int err; 197 198 backlight_disable(panel->backlight); 199 200 err = regmap_write(panel->map, NT39016_REG_SYSTEM, 201 NT39016_SYSTEM_RESET_N); 202 if (err) { 203 dev_err(panel->dev, "Unable to disable panel: %d", err); 204 return err; 205 } 206 207 return 0; 208 } 209 210 static int nt39016_get_modes(struct drm_panel *drm_panel, 211 struct drm_connector *connector) 212 { 213 struct nt39016 *panel = to_nt39016(drm_panel); 214 const struct nt39016_panel_info *panel_info = panel->panel_info; 215 struct drm_display_mode *mode; 216 unsigned int i; 217 218 for (i = 0; i < panel_info->num_modes; i++) { 219 mode = drm_mode_duplicate(connector->dev, 220 &panel_info->display_modes[i]); 221 if (!mode) 222 return -ENOMEM; 223 224 drm_mode_set_name(mode); 225 226 mode->type = DRM_MODE_TYPE_DRIVER; 227 if (panel_info->num_modes == 1) 228 mode->type |= DRM_MODE_TYPE_PREFERRED; 229 230 drm_mode_probed_add(connector, mode); 231 } 232 233 connector->display_info.bpc = 8; 234 connector->display_info.width_mm = panel_info->width_mm; 235 connector->display_info.height_mm = panel_info->height_mm; 236 237 drm_display_info_set_bus_formats(&connector->display_info, 238 &panel_info->bus_format, 1); 239 connector->display_info.bus_flags = panel_info->bus_flags; 240 241 return panel_info->num_modes; 242 } 243 244 static const struct drm_panel_funcs nt39016_funcs = { 245 .prepare = nt39016_prepare, 246 .unprepare = nt39016_unprepare, 247 .enable = nt39016_enable, 248 .disable = nt39016_disable, 249 .get_modes = nt39016_get_modes, 250 }; 251 252 static int nt39016_probe(struct spi_device *spi) 253 { 254 struct device *dev = &spi->dev; 255 struct nt39016 *panel; 256 int err; 257 258 panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); 259 if (!panel) 260 return -ENOMEM; 261 262 panel->dev = dev; 263 spi_set_drvdata(spi, panel); 264 265 panel->panel_info = of_device_get_match_data(dev); 266 if (!panel->panel_info) 267 return -EINVAL; 268 269 panel->supply = devm_regulator_get(dev, "power"); 270 if (IS_ERR(panel->supply)) { 271 dev_err(dev, "Failed to get power supply"); 272 return PTR_ERR(panel->supply); 273 } 274 275 panel->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); 276 if (IS_ERR(panel->reset_gpio)) { 277 dev_err(dev, "Failed to get reset GPIO"); 278 return PTR_ERR(panel->reset_gpio); 279 } 280 281 spi->bits_per_word = 8; 282 spi->mode = SPI_MODE_3 | SPI_3WIRE; 283 err = spi_setup(spi); 284 if (err) { 285 dev_err(dev, "Failed to setup SPI"); 286 return err; 287 } 288 289 panel->map = devm_regmap_init_spi(spi, &nt39016_regmap_config); 290 if (IS_ERR(panel->map)) { 291 dev_err(dev, "Failed to init regmap"); 292 return PTR_ERR(panel->map); 293 } 294 295 panel->backlight = devm_of_find_backlight(dev); 296 if (IS_ERR(panel->backlight)) { 297 err = PTR_ERR(panel->backlight); 298 if (err != -EPROBE_DEFER) 299 dev_err(dev, "Failed to get backlight handle"); 300 return err; 301 } 302 303 drm_panel_init(&panel->drm_panel, dev, &nt39016_funcs, 304 DRM_MODE_CONNECTOR_DPI); 305 306 err = drm_panel_add(&panel->drm_panel); 307 if (err < 0) { 308 dev_err(dev, "Failed to register panel"); 309 return err; 310 } 311 312 return 0; 313 } 314 315 static int nt39016_remove(struct spi_device *spi) 316 { 317 struct nt39016 *panel = spi_get_drvdata(spi); 318 319 drm_panel_remove(&panel->drm_panel); 320 321 nt39016_disable(&panel->drm_panel); 322 nt39016_unprepare(&panel->drm_panel); 323 324 return 0; 325 } 326 327 static const struct drm_display_mode kd035g6_display_modes[] = { 328 { /* 60 Hz */ 329 .clock = 6000, 330 .hdisplay = 320, 331 .hsync_start = 320 + 10, 332 .hsync_end = 320 + 10 + 50, 333 .htotal = 320 + 10 + 50 + 20, 334 .vdisplay = 240, 335 .vsync_start = 240 + 5, 336 .vsync_end = 240 + 5 + 1, 337 .vtotal = 240 + 5 + 1 + 4, 338 .vrefresh = 60, 339 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 340 }, 341 { /* 50 Hz */ 342 .clock = 5400, 343 .hdisplay = 320, 344 .hsync_start = 320 + 42, 345 .hsync_end = 320 + 42 + 50, 346 .htotal = 320 + 42 + 50 + 20, 347 .vdisplay = 240, 348 .vsync_start = 240 + 5, 349 .vsync_end = 240 + 5 + 1, 350 .vtotal = 240 + 5 + 1 + 4, 351 .vrefresh = 50, 352 .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, 353 }, 354 }; 355 356 static const struct nt39016_panel_info kd035g6_info = { 357 .display_modes = kd035g6_display_modes, 358 .num_modes = ARRAY_SIZE(kd035g6_display_modes), 359 .width_mm = 71, 360 .height_mm = 53, 361 .bus_format = MEDIA_BUS_FMT_RGB888_1X24, 362 .bus_flags = DRM_BUS_FLAG_PIXDATA_NEGEDGE, 363 }; 364 365 static const struct of_device_id nt39016_of_match[] = { 366 { .compatible = "kingdisplay,kd035g6-54nt", .data = &kd035g6_info }, 367 { /* sentinel */ } 368 }; 369 MODULE_DEVICE_TABLE(of, nt39016_of_match); 370 371 static struct spi_driver nt39016_driver = { 372 .driver = { 373 .name = "nt39016", 374 .of_match_table = nt39016_of_match, 375 }, 376 .probe = nt39016_probe, 377 .remove = nt39016_remove, 378 }; 379 380 module_spi_driver(nt39016_driver); 381 382 MODULE_AUTHOR("Maarten ter Huurne <maarten@treewalker.org>"); 383 MODULE_AUTHOR("Paul Cercueil <paul@crapouillou.net>"); 384 MODULE_LICENSE("GPL v2"); 385