panel-ilitek-ili9805.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 BSH Hausgerate GmbH
  4. */
  5. #include <linux/delay.h>
  6. #include <linux/device.h>
  7. #include <linux/err.h>
  8. #include <linux/errno.h>
  9. #include <linux/kernel.h>
  10. #include <linux/module.h>
  11. #include <linux/of.h>
  12. #include <linux/gpio/consumer.h>
  13. #include <linux/regulator/consumer.h>
  14. #include <drm/drm_mipi_dsi.h>
  15. #include <drm/drm_modes.h>
  16. #include <drm/drm_panel.h>
  17. #include <video/mipi_display.h>
  18. #define ILI9805_EXTCMD_CMD_SET_ENABLE_REG (0xff)
  19. #define ILI9805_SETEXTC_PARAMETER1 (0xff)
  20. #define ILI9805_SETEXTC_PARAMETER2 (0x98)
  21. #define ILI9805_SETEXTC_PARAMETER3 (0x05)
  22. #define ILI9805_INSTR(_delay, ...) { \
  23. .delay = (_delay), \
  24. .len = sizeof((u8[]) {__VA_ARGS__}), \
  25. .data = (u8[]){__VA_ARGS__} \
  26. }
  27. struct ili9805_instr {
  28. size_t len;
  29. const u8 *data;
  30. u32 delay;
  31. };
  32. struct ili9805_desc {
  33. const char *name;
  34. const struct ili9805_instr *init;
  35. const size_t init_length;
  36. const struct drm_display_mode *mode;
  37. u32 width_mm;
  38. u32 height_mm;
  39. };
  40. struct ili9805 {
  41. struct drm_panel panel;
  42. struct mipi_dsi_device *dsi;
  43. const struct ili9805_desc *desc;
  44. struct regulator *dvdd;
  45. struct regulator *avdd;
  46. struct gpio_desc *reset_gpio;
  47. };
  48. static const struct ili9805_instr gpm1780a0_init[] = {
  49. ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,
  50. ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),
  51. ILI9805_INSTR(100, 0xFD, 0x0F, 0x10, 0x44, 0x00),
  52. ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x00,
  53. 0x00, 0x30, 0x00, 0x00, 0x30, 0x00, 0x00),
  54. ILI9805_INSTR(0, 0xB8, 0x62),
  55. ILI9805_INSTR(0, 0xF1, 0x00),
  56. ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),
  57. ILI9805_INSTR(0, 0xF3, 0x60, 0x83, 0x04),
  58. ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),
  59. ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),
  60. ILI9805_INSTR(0, 0xe0, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,
  61. 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),
  62. ILI9805_INSTR(0, 0xe1, 0x00, 0x08, 0x0d, 0x0e, 0x0e, 0x0d, 0x0a, 0x08, 0x04,
  63. 0x08, 0x0d, 0x0f, 0x0b, 0x1c, 0x14, 0x0a),
  64. ILI9805_INSTR(10, 0xc1, 0x13, 0x39, 0x19, 0x06),
  65. ILI9805_INSTR(10, 0xc7, 0xe5),
  66. ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),
  67. ILI9805_INSTR(10, 0xB4, 0x02),
  68. ILI9805_INSTR(0, 0xBB, 0x14, 0x55),
  69. ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x08),
  70. ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),
  71. ILI9805_INSTR(0, 0x20),
  72. ILI9805_INSTR(0, 0xB0, 0x01),
  73. ILI9805_INSTR(0, 0xB6, 0x31, 0x00, 0xef),
  74. ILI9805_INSTR(0, 0xDF, 0x23),
  75. ILI9805_INSTR(0, 0xB9, 0x02, 0x00),
  76. };
  77. static const struct ili9805_instr tm041xdhg01_init[] = {
  78. ILI9805_INSTR(100, ILI9805_EXTCMD_CMD_SET_ENABLE_REG, ILI9805_SETEXTC_PARAMETER1,
  79. ILI9805_SETEXTC_PARAMETER2, ILI9805_SETEXTC_PARAMETER3),
  80. ILI9805_INSTR(100, 0xFD, 0x0F, 0x13, 0x44, 0x00),
  81. ILI9805_INSTR(0, 0xf8, 0x18, 0x02, 0x02, 0x18, 0x02, 0x02, 0x30, 0x01,
  82. 0x01, 0x30, 0x01, 0x01, 0x30, 0x01, 0x01),
  83. ILI9805_INSTR(0, 0xB8, 0x74),
  84. ILI9805_INSTR(0, 0xF1, 0x00),
  85. ILI9805_INSTR(0, 0xF2, 0x00, 0x58, 0x40),
  86. ILI9805_INSTR(0, 0xFC, 0x04, 0x0F, 0x01),
  87. ILI9805_INSTR(0, 0xEB, 0x08, 0x0F),
  88. ILI9805_INSTR(0, 0xe0, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,
  89. 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),
  90. ILI9805_INSTR(0, 0xe1, 0x01, 0x0d, 0x15, 0x0e, 0x0f, 0x0f, 0x0b, 0x08, 0x04,
  91. 0x07, 0x0a, 0x0d, 0x0c, 0x15, 0x0f, 0x08),
  92. ILI9805_INSTR(10, 0xc1, 0x15, 0x03, 0x03, 0x31),
  93. ILI9805_INSTR(10, 0xB1, 0x00, 0x12, 0x14),
  94. ILI9805_INSTR(10, 0xB4, 0x02),
  95. ILI9805_INSTR(0, 0xBB, 0x14, 0x55),
  96. ILI9805_INSTR(0, MIPI_DCS_SET_ADDRESS_MODE, 0x0a),
  97. ILI9805_INSTR(0, MIPI_DCS_SET_PIXEL_FORMAT, 0x77),
  98. ILI9805_INSTR(0, 0x20),
  99. ILI9805_INSTR(0, 0xB0, 0x00),
  100. ILI9805_INSTR(0, 0xB6, 0x01),
  101. ILI9805_INSTR(0, 0xc2, 0x11),
  102. ILI9805_INSTR(0, 0x51, 0xFF),
  103. ILI9805_INSTR(0, 0x53, 0x24),
  104. ILI9805_INSTR(0, 0x55, 0x00),
  105. };
  106. static inline struct ili9805 *panel_to_ili9805(struct drm_panel *panel)
  107. {
  108. return container_of(panel, struct ili9805, panel);
  109. }
  110. static int ili9805_power_on(struct ili9805 *ctx)
  111. {
  112. struct mipi_dsi_device *dsi = ctx->dsi;
  113. struct device *dev = &dsi->dev;
  114. int ret;
  115. ret = regulator_enable(ctx->avdd);
  116. if (ret) {
  117. dev_err(dev, "Failed to enable avdd regulator (%d)\n", ret);
  118. return ret;
  119. }
  120. ret = regulator_enable(ctx->dvdd);
  121. if (ret) {
  122. dev_err(dev, "Failed to enable dvdd regulator (%d)\n", ret);
  123. regulator_disable(ctx->avdd);
  124. return ret;
  125. }
  126. gpiod_set_value(ctx->reset_gpio, 0);
  127. usleep_range(5000, 10000);
  128. gpiod_set_value(ctx->reset_gpio, 1);
  129. msleep(120);
  130. return 0;
  131. }
  132. static int ili9805_power_off(struct ili9805 *ctx)
  133. {
  134. gpiod_set_value(ctx->reset_gpio, 0);
  135. regulator_disable(ctx->dvdd);
  136. regulator_disable(ctx->avdd);
  137. return 0;
  138. }
  139. static int ili9805_activate(struct ili9805 *ctx)
  140. {
  141. struct mipi_dsi_device *dsi = ctx->dsi;
  142. struct device *dev = &dsi->dev;
  143. int i, ret;
  144. for (i = 0; i < ctx->desc->init_length; i++) {
  145. const struct ili9805_instr *instr = &ctx->desc->init[i];
  146. ret = mipi_dsi_dcs_write_buffer(ctx->dsi, instr->data, instr->len);
  147. if (ret < 0)
  148. return ret;
  149. if (instr->delay > 0)
  150. msleep(instr->delay);
  151. }
  152. ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
  153. if (ret) {
  154. dev_err(dev, "Failed to exit sleep mode (%d)\n", ret);
  155. return ret;
  156. }
  157. usleep_range(5000, 6000);
  158. ret = mipi_dsi_dcs_set_display_on(ctx->dsi);
  159. if (ret) {
  160. dev_err(dev, "Failed to set display ON (%d)\n", ret);
  161. return ret;
  162. }
  163. return 0;
  164. }
  165. static int ili9805_prepare(struct drm_panel *panel)
  166. {
  167. struct ili9805 *ctx = panel_to_ili9805(panel);
  168. int ret;
  169. ret = ili9805_power_on(ctx);
  170. if (ret)
  171. return ret;
  172. ret = ili9805_activate(ctx);
  173. if (ret) {
  174. ili9805_power_off(ctx);
  175. return ret;
  176. }
  177. return 0;
  178. }
  179. static int ili9805_deactivate(struct ili9805 *ctx)
  180. {
  181. struct mipi_dsi_device *dsi = ctx->dsi;
  182. struct device *dev = &dsi->dev;
  183. int ret;
  184. ret = mipi_dsi_dcs_set_display_off(ctx->dsi);
  185. if (ret < 0) {
  186. dev_err(dev, "Failed to set display OFF (%d)\n", ret);
  187. return ret;
  188. }
  189. usleep_range(5000, 10000);
  190. ret = mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
  191. if (ret < 0) {
  192. dev_err(dev, "Failed to enter sleep mode (%d)\n", ret);
  193. return ret;
  194. }
  195. return 0;
  196. }
  197. static int ili9805_unprepare(struct drm_panel *panel)
  198. {
  199. struct ili9805 *ctx = panel_to_ili9805(panel);
  200. ili9805_deactivate(ctx);
  201. ili9805_power_off(ctx);
  202. return 0;
  203. }
  204. static const struct drm_display_mode gpm1780a0_timing = {
  205. .clock = 26227,
  206. .hdisplay = 480,
  207. .hsync_start = 480 + 10,
  208. .hsync_end = 480 + 10 + 2,
  209. .htotal = 480 + 10 + 2 + 36,
  210. .vdisplay = 480,
  211. .vsync_start = 480 + 2,
  212. .vsync_end = 480 + 10 + 4,
  213. .vtotal = 480 + 2 + 4 + 10,
  214. };
  215. static const struct drm_display_mode tm041xdhg01_timing = {
  216. .clock = 26227,
  217. .hdisplay = 480,
  218. .hsync_start = 480 + 10,
  219. .hsync_end = 480 + 10 + 2,
  220. .htotal = 480 + 10 + 2 + 36,
  221. .vdisplay = 768,
  222. .vsync_start = 768 + 2,
  223. .vsync_end = 768 + 10 + 4,
  224. .vtotal = 768 + 2 + 4 + 10,
  225. };
  226. static int ili9805_get_modes(struct drm_panel *panel,
  227. struct drm_connector *connector)
  228. {
  229. struct ili9805 *ctx = panel_to_ili9805(panel);
  230. struct drm_display_mode *mode;
  231. mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
  232. if (!mode) {
  233. dev_err(&ctx->dsi->dev, "failed to add mode %ux%ux@%u\n",
  234. ctx->desc->mode->hdisplay,
  235. ctx->desc->mode->vdisplay,
  236. drm_mode_vrefresh(ctx->desc->mode));
  237. return -ENOMEM;
  238. }
  239. drm_mode_set_name(mode);
  240. mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
  241. drm_mode_probed_add(connector, mode);
  242. connector->display_info.width_mm = mode->width_mm;
  243. connector->display_info.height_mm = mode->height_mm;
  244. return 1;
  245. }
  246. static const struct drm_panel_funcs ili9805_funcs = {
  247. .prepare = ili9805_prepare,
  248. .unprepare = ili9805_unprepare,
  249. .get_modes = ili9805_get_modes,
  250. };
  251. static int ili9805_dsi_probe(struct mipi_dsi_device *dsi)
  252. {
  253. struct ili9805 *ctx;
  254. int ret;
  255. ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
  256. if (!ctx)
  257. return -ENOMEM;
  258. mipi_dsi_set_drvdata(dsi, ctx);
  259. ctx->dsi = dsi;
  260. ctx->desc = of_device_get_match_data(&dsi->dev);
  261. dsi->format = MIPI_DSI_FMT_RGB888;
  262. dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
  263. MIPI_DSI_CLOCK_NON_CONTINUOUS | MIPI_DSI_MODE_LPM |
  264. MIPI_DSI_MODE_VIDEO_SYNC_PULSE | MIPI_DSI_MODE_NO_EOT_PACKET;
  265. dsi->lanes = 2;
  266. drm_panel_init(&ctx->panel, &dsi->dev, &ili9805_funcs,
  267. DRM_MODE_CONNECTOR_DSI);
  268. ctx->dvdd = devm_regulator_get(&dsi->dev, "dvdd");
  269. if (IS_ERR(ctx->dvdd))
  270. return PTR_ERR(ctx->dvdd);
  271. ctx->avdd = devm_regulator_get(&dsi->dev, "avdd");
  272. if (IS_ERR(ctx->avdd))
  273. return PTR_ERR(ctx->avdd);
  274. ctx->reset_gpio = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
  275. if (IS_ERR(ctx->reset_gpio)) {
  276. dev_err(&dsi->dev, "Couldn't get our reset GPIO\n");
  277. return PTR_ERR(ctx->reset_gpio);
  278. }
  279. ctx->panel.prepare_prev_first = true;
  280. ret = drm_panel_of_backlight(&ctx->panel);
  281. if (ret)
  282. return ret;
  283. drm_panel_add(&ctx->panel);
  284. ret = mipi_dsi_attach(dsi);
  285. if (ret < 0) {
  286. dev_err(&dsi->dev, "mipi_dsi_attach failed: %d\n", ret);
  287. drm_panel_remove(&ctx->panel);
  288. return ret;
  289. }
  290. return 0;
  291. }
  292. static void ili9805_dsi_remove(struct mipi_dsi_device *dsi)
  293. {
  294. struct ili9805 *ctx = mipi_dsi_get_drvdata(dsi);
  295. int ret;
  296. ret = mipi_dsi_detach(dsi);
  297. if (ret < 0)
  298. dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
  299. ret);
  300. drm_panel_remove(&ctx->panel);
  301. }
  302. static const struct ili9805_desc gpm1780a0_desc = {
  303. .init = gpm1780a0_init,
  304. .init_length = ARRAY_SIZE(gpm1780a0_init),
  305. .mode = &gpm1780a0_timing,
  306. .width_mm = 65,
  307. .height_mm = 65,
  308. };
  309. static const struct ili9805_desc tm041xdhg01_desc = {
  310. .init = tm041xdhg01_init,
  311. .init_length = ARRAY_SIZE(tm041xdhg01_init),
  312. .mode = &tm041xdhg01_timing,
  313. .width_mm = 42,
  314. .height_mm = 96,
  315. };
  316. static const struct of_device_id ili9805_of_match[] = {
  317. { .compatible = "giantplus,gpm1790a0", .data = &gpm1780a0_desc },
  318. { .compatible = "tianma,tm041xdhg01", .data = &tm041xdhg01_desc },
  319. { }
  320. };
  321. MODULE_DEVICE_TABLE(of, ili9805_of_match);
  322. static struct mipi_dsi_driver ili9805_dsi_driver = {
  323. .probe = ili9805_dsi_probe,
  324. .remove = ili9805_dsi_remove,
  325. .driver = {
  326. .name = "ili9805-dsi",
  327. .of_match_table = ili9805_of_match,
  328. },
  329. };
  330. module_mipi_dsi_driver(ili9805_dsi_driver);
  331. MODULE_AUTHOR("Matthias Proske <Matthias.Proske@bshg.com>");
  332. MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
  333. MODULE_DESCRIPTION("Ilitek ILI9805 Controller Driver");
  334. MODULE_LICENSE("GPL");