panel-sitronix-st7703.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639
  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. 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. ret = regulator_enable(ctx->vcc);
  372. if (ret < 0) {
  373. dev_err(ctx->dev, "Failed to enable vcc supply: %d\n", ret);
  374. return ret;
  375. }
  376. ret = regulator_enable(ctx->iovcc);
  377. if (ret < 0) {
  378. dev_err(ctx->dev, "Failed to enable iovcc supply: %d\n", ret);
  379. goto disable_vcc;
  380. }
  381. gpiod_set_value_cansleep(ctx->reset_gpio, 1);
  382. usleep_range(20, 40);
  383. gpiod_set_value_cansleep(ctx->reset_gpio, 0);
  384. msleep(20);
  385. ctx->prepared = true;
  386. return 0;
  387. disable_vcc:
  388. regulator_disable(ctx->vcc);
  389. return ret;
  390. }
  391. static int st7703_get_modes(struct drm_panel *panel,
  392. struct drm_connector *connector)
  393. {
  394. struct st7703 *ctx = panel_to_st7703(panel);
  395. struct drm_display_mode *mode;
  396. mode = drm_mode_duplicate(connector->dev, ctx->desc->mode);
  397. if (!mode) {
  398. dev_err(ctx->dev, "Failed to add mode %ux%u@%u\n",
  399. ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
  400. drm_mode_vrefresh(ctx->desc->mode));
  401. return -ENOMEM;
  402. }
  403. drm_mode_set_name(mode);
  404. mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
  405. connector->display_info.width_mm = mode->width_mm;
  406. connector->display_info.height_mm = mode->height_mm;
  407. drm_mode_probed_add(connector, mode);
  408. return 1;
  409. }
  410. static const struct drm_panel_funcs st7703_drm_funcs = {
  411. .disable = st7703_disable,
  412. .unprepare = st7703_unprepare,
  413. .prepare = st7703_prepare,
  414. .enable = st7703_enable,
  415. .get_modes = st7703_get_modes,
  416. };
  417. static int allpixelson_set(void *data, u64 val)
  418. {
  419. struct st7703 *ctx = data;
  420. struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
  421. dev_dbg(ctx->dev, "Setting all pixels on\n");
  422. dsi_generic_write_seq(dsi, ST7703_CMD_ALL_PIXEL_ON);
  423. msleep(val * 1000);
  424. /* Reset the panel to get video back */
  425. drm_panel_disable(&ctx->panel);
  426. drm_panel_unprepare(&ctx->panel);
  427. drm_panel_prepare(&ctx->panel);
  428. drm_panel_enable(&ctx->panel);
  429. return 0;
  430. }
  431. DEFINE_SIMPLE_ATTRIBUTE(allpixelson_fops, NULL,
  432. allpixelson_set, "%llu\n");
  433. static void st7703_debugfs_init(struct st7703 *ctx)
  434. {
  435. ctx->debugfs = debugfs_create_dir(DRV_NAME, NULL);
  436. debugfs_create_file("allpixelson", 0600, ctx->debugfs, ctx,
  437. &allpixelson_fops);
  438. }
  439. static void st7703_debugfs_remove(struct st7703 *ctx)
  440. {
  441. debugfs_remove_recursive(ctx->debugfs);
  442. ctx->debugfs = NULL;
  443. }
  444. static int st7703_probe(struct mipi_dsi_device *dsi)
  445. {
  446. struct device *dev = &dsi->dev;
  447. struct st7703 *ctx;
  448. int ret;
  449. ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
  450. if (!ctx)
  451. return -ENOMEM;
  452. ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
  453. if (IS_ERR(ctx->reset_gpio)) {
  454. dev_err(dev, "cannot get reset gpio\n");
  455. return PTR_ERR(ctx->reset_gpio);
  456. }
  457. mipi_dsi_set_drvdata(dsi, ctx);
  458. ctx->dev = dev;
  459. ctx->desc = of_device_get_match_data(dev);
  460. dsi->mode_flags = ctx->desc->mode_flags;
  461. dsi->format = ctx->desc->format;
  462. dsi->lanes = ctx->desc->lanes;
  463. ctx->vcc = devm_regulator_get(dev, "vcc");
  464. if (IS_ERR(ctx->vcc)) {
  465. ret = PTR_ERR(ctx->vcc);
  466. if (ret != -EPROBE_DEFER)
  467. dev_err(dev, "Failed to request vcc regulator: %d\n", ret);
  468. return ret;
  469. }
  470. ctx->iovcc = devm_regulator_get(dev, "iovcc");
  471. if (IS_ERR(ctx->iovcc)) {
  472. ret = PTR_ERR(ctx->iovcc);
  473. if (ret != -EPROBE_DEFER)
  474. dev_err(dev, "Failed to request iovcc regulator: %d\n", ret);
  475. return ret;
  476. }
  477. drm_panel_init(&ctx->panel, dev, &st7703_drm_funcs,
  478. DRM_MODE_CONNECTOR_DSI);
  479. ret = drm_panel_of_backlight(&ctx->panel);
  480. if (ret)
  481. return ret;
  482. drm_panel_add(&ctx->panel);
  483. ret = mipi_dsi_attach(dsi);
  484. if (ret < 0) {
  485. dev_err(dev, "mipi_dsi_attach failed (%d). Is host ready?\n", ret);
  486. drm_panel_remove(&ctx->panel);
  487. return ret;
  488. }
  489. dev_info(dev, "%ux%u@%u %ubpp dsi %udl - ready\n",
  490. ctx->desc->mode->hdisplay, ctx->desc->mode->vdisplay,
  491. drm_mode_vrefresh(ctx->desc->mode),
  492. mipi_dsi_pixel_format_to_bpp(dsi->format), dsi->lanes);
  493. st7703_debugfs_init(ctx);
  494. return 0;
  495. }
  496. static void st7703_shutdown(struct mipi_dsi_device *dsi)
  497. {
  498. struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
  499. int ret;
  500. ret = drm_panel_unprepare(&ctx->panel);
  501. if (ret < 0)
  502. dev_err(&dsi->dev, "Failed to unprepare panel: %d\n", ret);
  503. ret = drm_panel_disable(&ctx->panel);
  504. if (ret < 0)
  505. dev_err(&dsi->dev, "Failed to disable panel: %d\n", ret);
  506. }
  507. static int st7703_remove(struct mipi_dsi_device *dsi)
  508. {
  509. struct st7703 *ctx = mipi_dsi_get_drvdata(dsi);
  510. int ret;
  511. st7703_shutdown(dsi);
  512. ret = mipi_dsi_detach(dsi);
  513. if (ret < 0)
  514. dev_err(&dsi->dev, "Failed to detach from DSI host: %d\n", ret);
  515. drm_panel_remove(&ctx->panel);
  516. st7703_debugfs_remove(ctx);
  517. return 0;
  518. }
  519. static const struct of_device_id st7703_of_match[] = {
  520. { .compatible = "rocktech,jh057n00900", .data = &jh057n00900_panel_desc },
  521. { .compatible = "xingbangda,xbd599", .data = &xbd599_desc },
  522. { /* sentinel */ }
  523. };
  524. MODULE_DEVICE_TABLE(of, st7703_of_match);
  525. static struct mipi_dsi_driver st7703_driver = {
  526. .probe = st7703_probe,
  527. .remove = st7703_remove,
  528. .shutdown = st7703_shutdown,
  529. .driver = {
  530. .name = DRV_NAME,
  531. .of_match_table = st7703_of_match,
  532. },
  533. };
  534. module_mipi_dsi_driver(st7703_driver);
  535. MODULE_AUTHOR("Guido Günther <agx@sigxcpu.org>");
  536. MODULE_DESCRIPTION("DRM driver for Sitronix ST7703 based MIPI DSI panels");
  537. MODULE_LICENSE("GPL v2");