renesas-r69328.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * Renesas R69328 panel driver
  4. *
  5. * Copyright (c) 2022 Svyatoslav Ryhel <clamor95@gmail.com>
  6. */
  7. #include <common.h>
  8. #include <backlight.h>
  9. #include <dm.h>
  10. #include <panel.h>
  11. #include <log.h>
  12. #include <misc.h>
  13. #include <mipi_display.h>
  14. #include <mipi_dsi.h>
  15. #include <asm/gpio.h>
  16. #include <linux/delay.h>
  17. #include <linux/err.h>
  18. #include <power/regulator.h>
  19. /*
  20. * The datasheet is not publicly available, all values are
  21. * taken from the downstream. If you have access to datasheets,
  22. * corrections are welcome.
  23. */
  24. #define R69328_MACP 0xB0 /* Manufacturer Command Access Protect */
  25. #define R69328_GAMMA_SET_A 0xC8 /* Gamma Setting A */
  26. #define R69328_GAMMA_SET_B 0xC9 /* Gamma Setting B */
  27. #define R69328_GAMMA_SET_C 0xCA /* Gamma Setting C */
  28. #define R69328_POWER_SET 0xD1
  29. struct renesas_r69328_priv {
  30. struct udevice *backlight;
  31. struct gpio_desc enable_gpio;
  32. struct gpio_desc reset_gpio;
  33. };
  34. static const u8 address_mode[] = {
  35. MIPI_DCS_SET_ADDRESS_MODE
  36. };
  37. #define dsi_generic_write_seq(dsi, cmd, seq...) do { \
  38. static const u8 b[] = { cmd, seq }; \
  39. int ret; \
  40. ret = mipi_dsi_dcs_write_buffer(dsi, b, ARRAY_SIZE(b)); \
  41. if (ret < 0) \
  42. return ret; \
  43. } while (0)
  44. static struct display_timing default_timing = {
  45. .pixelclock.typ = 68000000,
  46. .hactive.typ = 720,
  47. .hfront_porch.typ = 92,
  48. .hback_porch.typ = 62,
  49. .hsync_len.typ = 4,
  50. .vactive.typ = 1280,
  51. .vfront_porch.typ = 6,
  52. .vback_porch.typ = 3,
  53. .vsync_len.typ = 1,
  54. };
  55. static int renesas_r69328_enable_backlight(struct udevice *dev)
  56. {
  57. struct renesas_r69328_priv *priv = dev_get_priv(dev);
  58. int ret;
  59. ret = dm_gpio_set_value(&priv->enable_gpio, 1);
  60. if (ret) {
  61. log_err("error changing enable-gpios (%d)\n", ret);
  62. return ret;
  63. }
  64. mdelay(5);
  65. ret = dm_gpio_set_value(&priv->reset_gpio, 0);
  66. if (ret) {
  67. log_err("error changing reset-gpios (%d)\n", ret);
  68. return ret;
  69. }
  70. mdelay(5);
  71. ret = dm_gpio_set_value(&priv->reset_gpio, 1);
  72. if (ret) {
  73. log_err("error changing reset-gpios (%d)\n", ret);
  74. return ret;
  75. }
  76. mdelay(5);
  77. return 0;
  78. }
  79. static int renesas_r69328_set_backlight(struct udevice *dev, int percent)
  80. {
  81. struct renesas_r69328_priv *priv = dev_get_priv(dev);
  82. struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
  83. struct mipi_dsi_device *dsi = plat->device;
  84. int ret;
  85. mipi_dsi_dcs_write_buffer(dsi, address_mode,
  86. sizeof(address_mode));
  87. ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
  88. if (ret < 0) {
  89. log_err("failed to set pixel format: %d\n", ret);
  90. return ret;
  91. }
  92. ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
  93. if (ret < 0) {
  94. log_err("failed to exit sleep mode: %d\n", ret);
  95. return ret;
  96. }
  97. mdelay(100);
  98. /* MACP Off */
  99. dsi_generic_write_seq(dsi, R69328_MACP, 0x04);
  100. dsi_generic_write_seq(dsi, R69328_POWER_SET, 0x14,
  101. 0x1d, 0x21, 0x67, 0x11, 0x9a);
  102. dsi_generic_write_seq(dsi, R69328_GAMMA_SET_A, 0x00,
  103. 0x1a, 0x20, 0x28, 0x25, 0x24,
  104. 0x26, 0x15, 0x13, 0x11, 0x18,
  105. 0x1e, 0x1c, 0x00, 0x00, 0x1a,
  106. 0x20, 0x28, 0x25, 0x24, 0x26,
  107. 0x15, 0x13, 0x11, 0x18, 0x1e,
  108. 0x1c, 0x00);
  109. dsi_generic_write_seq(dsi, R69328_GAMMA_SET_B, 0x00,
  110. 0x1a, 0x20, 0x28, 0x25, 0x24,
  111. 0x26, 0x15, 0x13, 0x11, 0x18,
  112. 0x1e, 0x1c, 0x00, 0x00, 0x1a,
  113. 0x20, 0x28, 0x25, 0x24, 0x26,
  114. 0x15, 0x13, 0x11, 0x18, 0x1e,
  115. 0x1c, 0x00);
  116. dsi_generic_write_seq(dsi, R69328_GAMMA_SET_C, 0x00,
  117. 0x1a, 0x20, 0x28, 0x25, 0x24,
  118. 0x26, 0x15, 0x13, 0x11, 0x18,
  119. 0x1e, 0x1c, 0x00, 0x00, 0x1a,
  120. 0x20, 0x28, 0x25, 0x24, 0x26,
  121. 0x15, 0x13, 0x11, 0x18, 0x1e,
  122. 0x1c, 0x00);
  123. /* MACP On */
  124. dsi_generic_write_seq(dsi, R69328_MACP, 0x03);
  125. ret = mipi_dsi_dcs_set_display_on(dsi);
  126. if (ret < 0) {
  127. log_err("failed to set display on: %d\n", ret);
  128. return ret;
  129. }
  130. mdelay(50);
  131. ret = backlight_enable(priv->backlight);
  132. if (ret)
  133. return ret;
  134. ret = backlight_set_brightness(priv->backlight, percent);
  135. if (ret)
  136. return ret;
  137. return 0;
  138. }
  139. static int renesas_r69328_timings(struct udevice *dev,
  140. struct display_timing *timing)
  141. {
  142. memcpy(timing, &default_timing, sizeof(*timing));
  143. return 0;
  144. }
  145. static int renesas_r69328_of_to_plat(struct udevice *dev)
  146. {
  147. struct renesas_r69328_priv *priv = dev_get_priv(dev);
  148. int ret;
  149. ret = uclass_get_device_by_phandle(UCLASS_PANEL_BACKLIGHT, dev,
  150. "backlight", &priv->backlight);
  151. if (ret) {
  152. log_err("cannot get backlight: ret = %d\n", ret);
  153. return ret;
  154. }
  155. ret = gpio_request_by_name(dev, "enable-gpios", 0,
  156. &priv->enable_gpio, GPIOD_IS_OUT);
  157. if (ret) {
  158. log_err("could not decode enable-gpios (%d)\n", ret);
  159. return ret;
  160. }
  161. ret = gpio_request_by_name(dev, "reset-gpios", 0,
  162. &priv->reset_gpio, GPIOD_IS_OUT);
  163. if (ret) {
  164. log_err("could not decode reser-gpios (%d)\n", ret);
  165. return ret;
  166. }
  167. return 0;
  168. }
  169. static int renesas_r69328_probe(struct udevice *dev)
  170. {
  171. struct mipi_dsi_panel_plat *plat = dev_get_plat(dev);
  172. /* fill characteristics of DSI data link */
  173. plat->lanes = 4;
  174. plat->format = MIPI_DSI_FMT_RGB888;
  175. plat->mode_flags = MIPI_DSI_MODE_VIDEO;
  176. return 0;
  177. }
  178. static const struct panel_ops renesas_r69328_ops = {
  179. .enable_backlight = renesas_r69328_enable_backlight,
  180. .set_backlight = renesas_r69328_set_backlight,
  181. .get_display_timing = renesas_r69328_timings,
  182. };
  183. static const struct udevice_id renesas_r69328_ids[] = {
  184. { .compatible = "jdi,dx12d100vm0eaa" },
  185. { }
  186. };
  187. U_BOOT_DRIVER(renesas_r69328) = {
  188. .name = "renesas_r69328",
  189. .id = UCLASS_PANEL,
  190. .of_match = renesas_r69328_ids,
  191. .ops = &renesas_r69328_ops,
  192. .of_to_plat = renesas_r69328_of_to_plat,
  193. .probe = renesas_r69328_probe,
  194. .plat_auto = sizeof(struct mipi_dsi_panel_plat),
  195. .priv_auto = sizeof(struct renesas_r69328_priv),
  196. };