You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

215 lines
5.4 KiB

  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * FB driver for the ST7789V LCD Controller
  4. *
  5. * Copyright (C) 2015 Dennis Menschel
  6. */
  7. #include <linux/bitops.h>
  8. #include <linux/delay.h>
  9. #include <linux/init.h>
  10. #include <linux/kernel.h>
  11. #include <linux/module.h>
  12. #include <video/mipi_display.h>
  13. #include "fbtft.h"
  14. #define DRVNAME "fb_st7789v"
  15. static unsigned int width;
  16. module_param(width, uint, 0000);
  17. MODULE_PARM_DESC(width, "Display width");
  18. static unsigned int height;
  19. module_param(height, uint, 0000);
  20. MODULE_PARM_DESC(height, "Display height");
  21. static u32 col_offset = 0;
  22. static u32 row_offset = 0;
  23. static u8 col_hack_fix_offset = 0;
  24. static short x_offset = 0;
  25. static short y_offset = 0;
  26. #define ST77XX_MADCTL_MY 0x80
  27. #define ST77XX_MADCTL_MX 0x40
  28. #define ST77XX_MADCTL_MV 0x20
  29. #define ST77XX_MADCTL_ML 0x10
  30. #define ST77XX_MADCTL_BGR 0x08
  31. #define ST77XX_MADCTL_RGB 0x00
  32. #define DEFAULT_GAMMA \
  33. "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25\n" \
  34. "70 2C 2E 15 10 09 48 33 53 0B 19 18 20 25"
  35. /**
  36. * enum st7789v_command - ST7789V display controller commands
  37. *
  38. * @PORCTRL: porch setting
  39. * @GCTRL: gate control
  40. * @VCOMS: VCOM setting
  41. * @VDVVRHEN: VDV and VRH command enable
  42. * @VRHS: VRH set
  43. * @VDVS: VDV set
  44. * @VCMOFSET: VCOM offset set
  45. * @PWCTRL1: power control 1
  46. * @PVGAMCTRL: positive voltage gamma control
  47. * @NVGAMCTRL: negative voltage gamma control
  48. *
  49. * The command names are the same as those found in the datasheet to ease
  50. * looking up their semantics and usage.
  51. *
  52. * Note that the ST7789V display controller offers quite a few more commands
  53. * which have been omitted from this list as they are not used at the moment.
  54. * Furthermore, commands that are compliant with the MIPI DCS have been left
  55. * out as well to avoid duplicate entries.
  56. */
  57. enum st7789v_command {
  58. PORCTRL = 0xB2,
  59. GCTRL = 0xB7,
  60. VCOMS = 0xBB,
  61. VDVVRHEN = 0xC2,
  62. VRHS = 0xC3,
  63. VDVS = 0xC4,
  64. VCMOFSET = 0xC5,
  65. PWCTRL1 = 0xD0,
  66. PVGAMCTRL = 0xE0,
  67. NVGAMCTRL = 0xE1,
  68. };
  69. /**
  70. * init_display() - initialize the display controller
  71. *
  72. * @par: FBTFT parameter object
  73. *
  74. * Most of the commands in this init function set their parameters to the
  75. * same default values which are already in place after the display has been
  76. * powered up. (The main exception to this rule is the pixel format which
  77. * would default to 18 instead of 16 bit per pixel.)
  78. * Nonetheless, this sequence can be used as a template for concrete
  79. * displays which usually need some adjustments.
  80. *
  81. * Return: 0 on success, < 0 if error occurred.
  82. */
  83. static int init_display(struct fbtft_par *par)
  84. {
  85. printk(KERN_INFO "ST7789 adafruit fbtft driver\n");
  86. width = par->info->var.xres;
  87. height = par->info->var.yres;
  88. if ((width == 0) || (width > 240)) {
  89. width = 240;
  90. }
  91. if ((height == 0) || (height > 320)) {
  92. height = 320;
  93. }
  94. printk(KERN_INFO "Size: (%d, %d)\n", width, height);
  95. // Go to sleep
  96. write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
  97. // Soft reset
  98. write_reg(par, MIPI_DCS_SOFT_RESET);
  99. mdelay(150);
  100. /* turn off sleep mode */
  101. write_reg(par, MIPI_DCS_EXIT_SLEEP_MODE);
  102. mdelay(10);
  103. /* set pixel format to RGB-565 */
  104. write_reg(par, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT);
  105. write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, 0);
  106. write_reg(par, MIPI_DCS_SET_COLUMN_ADDRESS, 0, 0, 0, 240);
  107. write_reg(par, MIPI_DCS_SET_PAGE_ADDRESS, 0, 0, 320>>8, 320&0xFF);
  108. write_reg(par, MIPI_DCS_ENTER_INVERT_MODE); // odd hack, displays are inverted
  109. write_reg(par, MIPI_DCS_ENTER_NORMAL_MODE);
  110. mdelay(10);
  111. write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
  112. return 0;
  113. }
  114. /**
  115. * set_var() - apply LCD properties like rotation and BGR mode
  116. *
  117. * @par: FBTFT parameter object
  118. *
  119. * Return: 0 on success, < 0 if error occurred.
  120. */
  121. static int set_var(struct fbtft_par *par)
  122. {
  123. u8 addr_mode = 0;
  124. switch (par->info->var.rotate) {
  125. case 0:
  126. addr_mode = 0;
  127. x_offset = col_offset;
  128. y_offset = row_offset;
  129. break;
  130. case 90:
  131. addr_mode = ST77XX_MADCTL_MV | ST77XX_MADCTL_MX;
  132. x_offset = row_offset;
  133. y_offset = col_offset;
  134. break;
  135. case 180:
  136. addr_mode = ST77XX_MADCTL_MX | ST77XX_MADCTL_MY;
  137. x_offset = (240 - width) - col_offset + col_hack_fix_offset;
  138. // hack tweak to account for extra pixel width to make even
  139. y_offset = (320 - height) - row_offset;
  140. break;
  141. case 270:
  142. addr_mode = ST77XX_MADCTL_MV | ST77XX_MADCTL_MY;
  143. x_offset = (320 - height) - row_offset;
  144. y_offset = (240 - width) - col_offset;
  145. break;
  146. default:
  147. return -EINVAL;
  148. }
  149. printk(KERN_INFO "Rotation %d offsets %d %d\n", par->info->var.rotate, x_offset, y_offset);
  150. write_reg(par, MIPI_DCS_SET_ADDRESS_MODE, addr_mode);
  151. return 0;
  152. }
  153. /**
  154. * blank() - blank the display
  155. *
  156. * @par: FBTFT parameter object
  157. * @on: whether to enable or disable blanking the display
  158. *
  159. * Return: 0 on success, < 0 if error occurred.
  160. */
  161. static int blank(struct fbtft_par *par, bool on)
  162. {
  163. if (on)
  164. write_reg(par, MIPI_DCS_SET_DISPLAY_OFF);
  165. else
  166. write_reg(par, MIPI_DCS_SET_DISPLAY_ON);
  167. return 0;
  168. }
  169. static struct fbtft_display display = {
  170. .regwidth = 8,
  171. .width = 240,
  172. .height = 320,
  173. .gamma_num = 2,
  174. .gamma_len = 14,
  175. .gamma = DEFAULT_GAMMA,
  176. .fbtftops = {
  177. .init_display = init_display,
  178. .set_var = set_var,
  179. .blank = blank,
  180. },
  181. };
  182. FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7789v", &display);
  183. MODULE_ALIAS("spi:" DRVNAME);
  184. MODULE_ALIAS("platform:" DRVNAME);
  185. MODULE_ALIAS("spi:st7789v");
  186. MODULE_ALIAS("platform:st7789v");
  187. MODULE_DESCRIPTION("FB driver for the ST7789V LCD Controller");
  188. MODULE_AUTHOR("Dennis Menschel");
  189. MODULE_LICENSE("GPL");