panel-novatek-nt39016.c 9.0 KB

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