panel-sitronix-st7703.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Driver for panels based on Sitronix ST7703 controller, souch as:
  4. *
  5. * - Rocktech jh057n00900 5.5" MIPI-DSI panel
  6. *
  7. * Copyright (C) Purism SPC 2019
  8. */
  9. #include <linux/debugfs.h>
  10. #include <linux/delay.h>
  11. #include <linux/gpio/consumer.h>
  12. #include <linux/media-bus-format.h>
  13. #include <linux/mod_devicetable.h>
  14. #include <linux/module.h>
  15. #include <linux/of_device.h>
  16. #include <linux/regulator/consumer.h>
  17. #include <video/display_timing.h>
  18. #include <video/mipi_display.h>
  19. #include <drm/drm_mipi_dsi.h>
  20. #include <drm/drm_modes.h>
  21. #include <drm/drm_panel.h>
  22. #define DRV_NAME "panel-sitronix-st7703"
  23. /* Manufacturer specific Commands send via DSI */
  24. #define ST7703_CMD_ALL_PIXEL_OFF 0x22
  25. #define ST7703_CMD_ALL_PIXEL_ON 0x23
  26. #define ST7703_CMD_SETDISP 0xB2
  27. #define ST7703_CMD_SETRGBIF 0xB3
  28. #define ST7703_CMD_SETCYC 0xB4
  29. #define ST7703_CMD_SETBGP 0xB5
  30. #define ST7703_CMD_SETVCOM 0xB6
  31. #define ST7703_CMD_SETOTP 0xB7
  32. #define ST7703_CMD_SETPOWER_EXT 0xB8
  33. #define ST7703_CMD_SETEXTC 0xB9
  34. #define ST7703_CMD_SETMIPI 0xBA
  35. #define ST7703_CMD_SETVDC 0xBC
  36. #define ST7703_CMD_UNKNOWN_BF 0xBF
  37. #define ST7703_CMD_SETSCR 0xC0
  38. #define ST7703_CMD_SETPOWER 0xC1
  39. #define ST7703_CMD_SETPANEL 0xCC
  40. #define ST7703_CMD_UNKNOWN_C6 0xC6
  41. #define ST7703_CMD_SETGAMMA 0xE0
  42. #define ST7703_CMD_SETEQ 0xE3
  43. #define ST7703_CMD_SETGIP1 0xE9
  44. #define ST7703_CMD_SETGIP2 0xEA
  45. struct st7703 {
  46. struct device *dev;
  47. struct drm_panel panel;
  48. struct gpio_desc *reset_gpio;
  49. struct regulator *vcc;
  50. struct regulator *iovcc;
  51. bool prepared;
  52. struct dentry *debugfs;
  53. const struct st7703_panel_desc *desc;
  54. };
  55. struct st7703_panel_desc {
  56. const struct drm_display_mode *mode;
  57. unsigned int lanes;
  58. unsigned long mode_flags;
  59. enum mipi_dsi_pixel_format format;
  60. int (*init_sequence)(struct st7703 *ctx);
  61. };
  62. static inline struct st7703 *panel_to_st7703(struct drm_panel *panel)
  63. {
  64. return container_of(panel, struct st7703, panel);
  65. }
  66. #define dsi_generic_write_seq(dsi, seq...) do { \
  67. static const u8 d[] = { seq }; \
  68. int ret; \
  69. ret = mipi_dsi_generic_write(dsi, d, ARRAY_SIZE(d)); \
  70. if (ret < 0) \
  71. return ret; \
  72. } while (0)
  73. static int jh057n_init_sequence(struct st7703 *ctx)
  74. {
  75. struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  76. /*
  77. * Init sequence was supplied by the panel vendor. Most of the commands
  78. * resemble the ST7703 but the number of parameters often don't match
  79. * so it's likely a clone.
  80. */
  81. dsi_generic_write_seq(dsi, ST7703_CMD_SETEXTC,
  82. 0xF1, 0x12, 0x83);
  83. dsi_generic_write_seq(dsi, ST7703_CMD_SETRGBIF,
  84. 0x10, 0x10, 0x05, 0x05, 0x03, 0xFF, 0x00, 0x00,
  85. 0x00, 0x00);
  86. dsi_generic_write_seq(dsi, ST7703_CMD_SETSCR,
  87. 0x73, 0x73, 0x50, 0x50, 0x00, 0x00, 0x08, 0x70,
  88. 0x00);
  89. dsi_generic_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
  90. dsi_generic_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
  91. dsi_generic_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
  92. dsi_generic_write_seq(dsi, ST7703_CMD_SETDISP, 0xF0, 0x12, 0x30);
  93. dsi_generic_write_seq(dsi, ST7703_CMD_SETEQ,
  94. 0x07, 0x07, 0x0B, 0x0B, 0x03, 0x0B, 0x00, 0x00,
  95. 0x00, 0x00, 0xFF, 0x00, 0xC0, 0x10);
  96. dsi_generic_write_seq(dsi, ST7703_CMD_SETBGP, 0x08, 0x08);
  97. msleep(20);
  98. dsi_generic_write_seq(dsi, ST7703_CMD_SETVCOM, 0x3F, 0x3F);
  99. dsi_generic_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
  100. dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP1,
  101. 0x82, 0x10, 0x06, 0x05, 0x9E, 0x0A, 0xA5, 0x12,
  102. 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
  103. 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
  104. 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
  105. 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
  106. 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
  107. 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  108. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
  109. dsi_generic_write_seq(dsi, ST7703_CMD_SETGIP2,
  110. 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  111. 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
  112. 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
  113. 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
  114. 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
  115. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  116. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x0A,
  117. 0xA5, 0x00, 0x00, 0x00, 0x00);
  118. dsi_generic_write_seq(dsi, ST7703_CMD_SETGAMMA,
  119. 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41, 0x37,
  120. 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10, 0x11,
  121. 0x18, 0x00, 0x09, 0x0E, 0x29, 0x2D, 0x3C, 0x41,
  122. 0x37, 0x07, 0x0B, 0x0D, 0x10, 0x11, 0x0F, 0x10,
  123. 0x11, 0x18);
  124. return 0;
  125. }
  126. static const struct drm_display_mode jh057n00900_mode = {
  127. .hdisplay = 720,
  128. .hsync_start = 720 + 90,
  129. .hsync_end = 720 + 90 + 20,
  130. .htotal = 720 + 90 + 20 + 20,
  131. .vdisplay = 1440,
  132. .vsync_start = 1440 + 20,
  133. .vsync_end = 1440 + 20 + 4,
  134. .vtotal = 1440 + 20 + 4 + 12,
  135. .clock = 75276,
  136. .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
  137. .width_mm = 65,
  138. .height_mm = 130,
  139. };
  140. static const struct st7703_panel_desc jh057n00900_panel_desc = {
  141. .mode = &jh057n00900_mode,
  142. .lanes = 4,
  143. .mode_flags = MIPI_DSI_MODE_VIDEO |
  144. MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
  145. .format = MIPI_DSI_FMT_RGB888,
  146. .init_sequence = jh057n_init_sequence,
  147. };
  148. #define dsi_dcs_write_seq(dsi, cmd, seq...) do { \
  149. static const u8 d[] = { seq }; \
  150. int ret; \
  151. ret = mipi_dsi_dcs_write(dsi, cmd, d, ARRAY_SIZE(d)); \
  152. if (ret < 0) \
  153. return ret; \
  154. } while (0)
  155. static int xbd599_init_sequence(struct st7703 *ctx)
  156. {
  157. struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  158. /*
  159. * Init sequence was supplied by the panel vendor.
  160. */
  161. /* Magic sequence to unlock user commands below. */
  162. dsi_dcs_write_seq(dsi, ST7703_CMD_SETEXTC, 0xF1, 0x12, 0x83);
  163. dsi_dcs_write_seq(dsi, ST7703_CMD_SETMIPI,
  164. 0x33, /* VC_main = 0, Lane_Number = 3 (4 lanes) */
  165. 0x81, /* DSI_LDO_SEL = 1.7V, RTERM = 90 Ohm */
  166. 0x05, /* IHSRX = x6 (Low High Speed driving ability) */
  167. 0xF9, /* TX_CLK_SEL = fDSICLK/16 */
  168. 0x0E, /* HFP_OSC (min. HFP number in DSI mode) */
  169. 0x0E, /* HBP_OSC (min. HBP number in DSI mode) */
  170. /* The rest is undocumented in ST7703 datasheet */
  171. 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  172. 0x44, 0x25, 0x00, 0x91, 0x0a, 0x00, 0x00, 0x02,
  173. 0x4F, 0x11, 0x00, 0x00, 0x37);
  174. dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER_EXT,
  175. 0x25, /* PCCS = 2, ECP_DC_DIV = 1/4 HSYNC */
  176. 0x22, /* DT = 15ms XDK_ECP = x2 */
  177. 0x20, /* PFM_DC_DIV = /1 */
  178. 0x03 /* ECP_SYNC_EN = 1, VGX_SYNC_EN = 1 */);
  179. /* RGB I/F porch timing */
  180. dsi_dcs_write_seq(dsi, ST7703_CMD_SETRGBIF,
  181. 0x10, /* VBP_RGB_GEN */
  182. 0x10, /* VFP_RGB_GEN */
  183. 0x05, /* DE_BP_RGB_GEN */
  184. 0x05, /* DE_FP_RGB_GEN */
  185. /* The rest is undocumented in ST7703 datasheet */
  186. 0x03, 0xFF,
  187. 0x00, 0x00,
  188. 0x00, 0x00);
  189. /* Source driving settings. */
  190. dsi_dcs_write_seq(dsi, ST7703_CMD_SETSCR,
  191. 0x73, /* N_POPON */
  192. 0x73, /* N_NOPON */
  193. 0x50, /* I_POPON */
  194. 0x50, /* I_NOPON */
  195. 0x00, /* SCR[31,24] */
  196. 0xC0, /* SCR[23,16] */
  197. 0x08, /* SCR[15,8] */
  198. 0x70, /* SCR[7,0] */
  199. 0x00 /* Undocumented */);
  200. /* NVDDD_SEL = -1.8V, VDDD_SEL = out of range (possibly 1.9V?) */
  201. dsi_dcs_write_seq(dsi, ST7703_CMD_SETVDC, 0x4E);
  202. /*
  203. * SS_PANEL = 1 (reverse scan), GS_PANEL = 0 (normal scan)
  204. * REV_PANEL = 1 (normally black panel), BGR_PANEL = 1 (BGR)
  205. */
  206. dsi_dcs_write_seq(dsi, ST7703_CMD_SETPANEL, 0x0B);
  207. /* Zig-Zag Type C column inversion. */
  208. dsi_dcs_write_seq(dsi, ST7703_CMD_SETCYC, 0x80);
  209. /* Set display resolution. */
  210. dsi_dcs_write_seq(dsi, ST7703_CMD_SETDISP,
  211. 0xF0, /* NL = 240 */
  212. 0x12, /* RES_V_LSB = 0, BLK_CON = VSSD,
  213. * RESO_SEL = 720RGB
  214. */
  215. 0xF0 /* WHITE_GND_EN = 1 (GND),
  216. * WHITE_FRAME_SEL = 7 frames,
  217. * ISC = 0 frames
  218. */);
  219. dsi_dcs_write_seq(dsi, ST7703_CMD_SETEQ,
  220. 0x00, /* PNOEQ */
  221. 0x00, /* NNOEQ */
  222. 0x0B, /* PEQGND */
  223. 0x0B, /* NEQGND */
  224. 0x10, /* PEQVCI */
  225. 0x10, /* NEQVCI */
  226. 0x00, /* PEQVCI1 */
  227. 0x00, /* NEQVCI1 */
  228. 0x00, /* reserved */
  229. 0x00, /* reserved */
  230. 0xFF, /* reserved */
  231. 0x00, /* reserved */
  232. 0xC0, /* ESD_DET_DATA_WHITE = 1, ESD_WHITE_EN = 1 */
  233. 0x10 /* SLPIN_OPTION = 1 (no need vsync after sleep-in)
  234. * VEDIO_NO_CHECK_EN = 0
  235. * ESD_WHITE_GND_EN = 0
  236. * ESD_DET_TIME_SEL = 0 frames
  237. */);
  238. /* Undocumented command. */
  239. dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_C6, 0x01, 0x00, 0xFF, 0xFF, 0x00);
  240. dsi_dcs_write_seq(dsi, ST7703_CMD_SETPOWER,
  241. 0x74, /* VBTHS, VBTLS: VGH = 17V, VBL = -11V */
  242. 0x00, /* FBOFF_VGH = 0, FBOFF_VGL = 0 */
  243. 0x32, /* VRP */
  244. 0x32, /* VRN */
  245. 0x77, /* reserved */
  246. 0xF1, /* APS = 1 (small),
  247. * VGL_DET_EN = 1, VGH_DET_EN = 1,
  248. * VGL_TURBO = 1, VGH_TURBO = 1
  249. */
  250. 0xFF, /* VGH1_L_DIV, VGL1_L_DIV (1.5MHz) */
  251. 0xFF, /* VGH1_R_DIV, VGL1_R_DIV (1.5MHz) */
  252. 0xCC, /* VGH2_L_DIV, VGL2_L_DIV (2.6MHz) */
  253. 0xCC, /* VGH2_R_DIV, VGL2_R_DIV (2.6MHz) */
  254. 0x77, /* VGH3_L_DIV, VGL3_L_DIV (4.5MHz) */
  255. 0x77 /* VGH3_R_DIV, VGL3_R_DIV (4.5MHz) */);
  256. /* Reference voltage. */
  257. dsi_dcs_write_seq(dsi, ST7703_CMD_SETBGP,
  258. 0x07, /* VREF_SEL = 4.2V */
  259. 0x07 /* NVREF_SEL = 4.2V */);
  260. msleep(20);
  261. dsi_dcs_write_seq(dsi, ST7703_CMD_SETVCOM,
  262. 0x2C, /* VCOMDC_F = -0.67V */
  263. 0x2C /* VCOMDC_B = -0.67V */);
  264. /* Undocumented command. */
  265. dsi_dcs_write_seq(dsi, ST7703_CMD_UNKNOWN_BF, 0x02, 0x11, 0x00);
  266. /* This command is to set forward GIP timing. */
  267. dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP1,
  268. 0x82, 0x10, 0x06, 0x05, 0xA2, 0x0A, 0xA5, 0x12,
  269. 0x31, 0x23, 0x37, 0x83, 0x04, 0xBC, 0x27, 0x38,
  270. 0x0C, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0C, 0x00,
  271. 0x03, 0x00, 0x00, 0x00, 0x75, 0x75, 0x31, 0x88,
  272. 0x88, 0x88, 0x88, 0x88, 0x88, 0x13, 0x88, 0x64,
  273. 0x64, 0x20, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
  274. 0x02, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  275. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
  276. /* This command is to set backward GIP timing. */
  277. dsi_dcs_write_seq(dsi, ST7703_CMD_SETGIP2,
  278. 0x02, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  279. 0x00, 0x00, 0x00, 0x00, 0x02, 0x46, 0x02, 0x88,
  280. 0x88, 0x88, 0x88, 0x88, 0x88, 0x64, 0x88, 0x13,
  281. 0x57, 0x13, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
  282. 0x75, 0x88, 0x23, 0x14, 0x00, 0x00, 0x02, 0x00,
  283. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  284. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0A,
  285. 0xA5, 0x00, 0x00, 0x00, 0x00);
  286. /* Adjust the gamma characteristics of the panel. */
  287. dsi_dcs_write_seq(dsi, ST7703_CMD_SETGAMMA,
  288. 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41, 0x35,
  289. 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12, 0x12,
  290. 0x18, 0x00, 0x09, 0x0D, 0x23, 0x27, 0x3C, 0x41,
  291. 0x35, 0x07, 0x0D, 0x0E, 0x12, 0x13, 0x10, 0x12,
  292. 0x12, 0x18);
  293. return 0;
  294. }
  295. static const struct drm_display_mode xbd599_mode = {
  296. .hdisplay = 720,
  297. .hsync_start = 720 + 40,
  298. .hsync_end = 720 + 40 + 40,
  299. .htotal = 720 + 40 + 40 + 40,
  300. .vdisplay = 1440,
  301. .vsync_start = 1440 + 18,
  302. .vsync_end = 1440 + 18 + 10,
  303. .vtotal = 1440 + 18 + 10 + 17,
  304. .clock = 69000,
  305. .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
  306. .width_mm = 68,
  307. .height_mm = 136,
  308. };
  309. static const struct st7703_panel_desc xbd599_desc = {
  310. .mode = &xbd599_mode,
  311. .lanes = 4,
  312. .mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
  313. .format = MIPI_DSI_FMT_RGB888,
  314. .init_sequence = xbd599_init_sequence,
  315. };
  316. static int st7703_enable(struct drm_panel *panel)
  317. {
  318. struct st7703 *ctx = panel_to_st7703(panel);
  319. struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  320. int ret;
  321. ret = ctx->desc->init_sequence(ctx);
  322. if (ret < 0) {
  323. dev_err(ctx->dev, "Panel init sequence failed: %d\n", ret);
  324. return ret;
  325. }
  326. msleep(20);
  327. ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
  328. if (ret < 0) {
  329. dev_err(ctx->dev, "Failed to exit sleep mode: %d\n", ret);
  330. return ret;
  331. }
  332. /* Panel is operational 120 msec after reset */
  333. msleep(60);
  334. ret = mipi_dsi_dcs_set_display_on(dsi);
  335. if (ret)
  336. return ret;
  337. dev_dbg(ctx->dev, "Panel init sequence done\n");
  338. return 0;
  339. }
  340. static int st7703_disable(struct drm_panel *panel)
  341. {
  342. struct st7703 *ctx = panel_to_st7703(panel);
  343. struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  344. int ret;
  345. ret = mipi_dsi_dcs_set_display_off(dsi);
  346. if (ret < 0)
  347. dev_err(ctx->dev, "Failed to turn off the display: %d\n", ret);
  348. ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
  349. if (ret < 0)
  350. dev_err(ctx->dev, "Failed to enter sleep mode: %d\n", ret);
  351. return 0;
  352. }
  353. static int st7703_unprepare(struct drm_panel *panel)
  354. {
  355. struct st7703 *ctx = panel_to_st7703(panel);
  356. if (!ctx->prepared)
  357. return 0;
  358. gpiod_set_value_cansleep(ctx->reset_gpio, 1);
  359. regulator_disable(ctx->iovcc);
  360. regulator_disable(ctx->vcc);
  361. ctx->prepared = false;
  362. return 0;
  363. }
  364. static int st7703_prepare(struct drm_panel *panel)
  365. {
  366. struct st7703 *ctx = panel_to_st7703(panel);
  367. int ret;
  368. if (ctx->prepared)
  369. return 0;
  370. dev_dbg(ctx->dev, "Resetting the panel\n");
  371. gpiod_set_value_cansleep(ctx->reset_gpio, 1);
  372. ret = regulator_enable(ctx->iovcc);
  373. if (ret < 0) {
  374. dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
  375. return ret;
  376. }
  377. ret = regulator_enable(ctx->vcc);
  378. if (ret < 0) {
  379. dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
  380. regulator_disable(ctx->iovcc);
  381. return ret;
  382. }
  383. /* Give power supplies time to stabilize before deasserting reset. */
  384. usleep_range(10000, 20000);
  385. gpiod_set_value_cansleep(ctx->reset_gpio, 0);
  386. usleep_range(15000, 20000);
  387. ctx->prepared = true;
  388. return 0;
  389. }
  390. static const u32 mantix_bus_formats[] = {
  391. MEDIA_BUS_FMT_RGB888_1X24,
  392. };
  393. static int st7703_get_modes(struct drm_panel *panel,
  394. struct drm_connector *connector)
  395. {
  396. struct st7703 *ctx = panel_to_st7703(panel);
  397. struct drm_display_mode *mode;
  398. mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
  399. if (!mode) {
  400. dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
  401. ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
  402. drm_mode_vrefresh(ctx->desc->mode));
  403. return -ENOMEM;
  404. }
  405. drm_mode_set_name(mode);
  406. mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
  407. connector->display_info.width_mm = mode->width_mm;
  408. connector->display_info.height_mm = mode->height_mm;
  409. drm_mode_probed_add(connector, mode);
  410. drm_display_info_set_bus_formats(&connector->display_info,
  411. mantix_bus_formats,
  412. ARRAY_SIZE(mantix_bus_formats));
  413. return 1;
  414. }
  415. static const struct drm_panel_funcs st7703_drm_funcs = {
  416. .disable = st7703_disable,
  417. .unprepare = st7703_unprepare,
  418. .prepare = st7703_prepare,
  419. .enable = st7703_enable,
  420. .get_modes = st7703_get_modes,
  421. };
  422. static int allpixelson_set(void *data, u64 val)
  423. {
  424. struct st7703 *ctx = data;
  425. struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  426. dev_dbg(ctx->dev, "Setting all pixels on\n");
  427. dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
  428. msleep(val * 1000);
  429. /* Reset the panel to get video back */
  430. drm_panel_disable(&ctx->panel);
  431. drm_panel_unprepare(&ctx->panel);
  432. drm_panel_prepare(&ctx->panel);
  433. drm_panel_enable(&ctx->panel);
  434. return 0;
  435. }
  436. DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
  437. allpixelson_set, "%llu\n");
  438. static void st7703_debugfs_init(struct st7703 *ctx)
  439. {
  440. ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
  441. debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
  442. &allpixelson_fops);
  443. }
  444. static void st7703_debugfs_remove(struct st7703 *ctx)
  445. {
  446. debugfs_remove_recursive(ctx->debugfs);
  447. ctx->debugfs = NULL;
  448. }
  449. static int st7703_probe(struct mipi_dsi_device *dsi)
  450. {
  451. struct device *dev = &dsi->dev;
  452. struct st7703 *ctx;
  453. int ret;
  454. ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
  455. if (!ctx)
  456. return -ENOMEM;
  457. ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
  458. if (IS_ERR(ctx->reset_gpio))
  459. return dev_err_probe(dev, PTR_ERR(ctx->reset_gpio), "Failed to get reset gpio\n");
  460. mipi_dsi_set_drvdata(dsi, ctx);
  461. ctx->dev = dev;
  462. ctx->desc = of_device_get_match_data(dev);
  463. dsi->mode_flags = ctx->desc->mode_flags;
  464. dsi->format = ctx->desc->format;
  465. dsi->lanes = ctx->desc->lanes;
  466. ctx->vcc = devm_regulator_get(dev, "vcc");
  467. if (IS_ERR(ctx->vcc))
  468. return dev_err_probe(dev, PTR_ERR(ctx->vcc), "Failed to request vcc regulator\n");
  469. ctx->iovcc = devm_regulator_get(dev, "iovcc");
  470. if (IS_ERR(ctx->iovcc))
  471. return dev_err_probe(dev, PTR_ERR(ctx->iovcc),
  472. "Failed to request iovcc regulator\n");
  473. drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
  474. DRM_MODE_CONNECTOR_DSI);
  475. ret = drm_panel_of_backlight(&ctx->panel);
  476. if (ret)
  477. return ret;
  478. drm_panel_add(&ctx->panel);
  479. ret = mipi_dsi_attach(dsi);
  480. if (ret < 0) {
  481. dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
  482. drm_panel_remove(&ctx->panel);
  483. return ret;
  484. }
  485. dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
  486. ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
  487. drm_mode_vrefresh(ctx->desc->mode),
  488. mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
  489. st7703_debugfs_init(ctx);
  490. return 0;
  491. }
  492. static void st7703_shutdown(struct mipi_dsi_device *dsi)
  493. {
  494. struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
  495. int ret;
  496. ret = drm_panel_unprepare(&ctx->panel);
  497. if (ret < 0)
  498. dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
  499. ret = drm_panel_disable(&ctx->panel);
  500. if (ret < 0)
  501. dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
  502. }
  503. static void st7703_remove(struct mipi_dsi_device *dsi)
  504. {
  505. struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
  506. int ret;
  507. st7703_shutdown(dsi);
  508. ret = mipi_dsi_detach(dsi);
  509. if (ret < 0)
  510. dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
  511. drm_panel_remove(&ctx->panel);
  512. st7703_debugfs_remove(ctx);
  513. }
  514. static const struct of_device_id st7703_of_match[] = {
  515. { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
  516. { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
  517. { /* sentinel */ }
  518. };
  519. MODULE_DEVICE_TABLE(of, st7703_of_match);
  520. static struct mipi_dsi_driver st7703_driver = {
  521. .probe = st7703_probe,
  522. .remove = st7703_remove,
  523. .shutdown = st7703_shutdown,
  524. .driver = {
  525. .name = DRV_NAME,
  526. .of_match_table = st7703_of_match,
  527. },
  528. };
  529. module_mipi_dsi_driver(st7703_driver);
  530. MODULE_AUTHOR("Guido Günther <[email protected]>");
  531. MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
  532. MODULE_LICENSE("GPL v2");