panel-abt-y030xx067a.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Asia Better Technology Ltd. Y030XX067A IPS LCD panel driver
  4. *
  5. * Copyright (C) 2020, Paul Cercueil <[email protected]>
  6. * Copyright (C) 2020, Christophe Branchereau <[email protected]>
  7. */
  8. #include <linux/delay.h>
  9. #include <linux/device.h>
  10. #include <linux/gpio/consumer.h>
  11. #include <linux/media-bus-format.h>
  12. #include <linux/module.h>
  13. #include <linux/of_device.h>
  14. #include <linux/regmap.h>
  15. #include <linux/regulator/consumer.h>
  16. #include <linux/spi/spi.h>
  17. #include <drm/drm_modes.h>
  18. #include <drm/drm_panel.h>
  19. #define REG00_VBRT_CTRL(val) (val)
  20. #define REG01_COM_DC(val) (val)
  21. #define REG02_DA_CONTRAST(val) (val)
  22. #define REG02_VESA_SEL(val) ((val) << 5)
  23. #define REG02_COMDC_SW BIT(7)
  24. #define REG03_VPOSITION(val) (val)
  25. #define REG03_BSMOUNT BIT(5)
  26. #define REG03_COMTST BIT(6)
  27. #define REG03_HPOSITION1 BIT(7)
  28. #define REG04_HPOSITION1(val) (val)
  29. #define REG05_CLIP BIT(0)
  30. #define REG05_NVM_VREFRESH BIT(1)
  31. #define REG05_SLFR BIT(2)
  32. #define REG05_SLBRCHARGE(val) ((val) << 3)
  33. #define REG05_PRECHARGE_LEVEL(val) ((val) << 6)
  34. #define REG06_TEST5 BIT(0)
  35. #define REG06_SLDWN BIT(1)
  36. #define REG06_SLRGT BIT(2)
  37. #define REG06_TEST2 BIT(3)
  38. #define REG06_XPSAVE BIT(4)
  39. #define REG06_GAMMA_SEL(val) ((val) << 5)
  40. #define REG06_NT BIT(7)
  41. #define REG07_TEST1 BIT(0)
  42. #define REG07_HDVD_POL BIT(1)
  43. #define REG07_CK_POL BIT(2)
  44. #define REG07_TEST3 BIT(3)
  45. #define REG07_TEST4 BIT(4)
  46. #define REG07_480_LINEMASK BIT(5)
  47. #define REG07_AMPTST(val) ((val) << 6)
  48. #define REG08_SLHRC(val) (val)
  49. #define REG08_CLOCK_DIV(val) ((val) << 2)
  50. #define REG08_PANEL(val) ((val) << 5)
  51. #define REG09_SUB_BRIGHT_R(val) (val)
  52. #define REG09_NW_NB BIT(6)
  53. #define REG09_IPCON BIT(7)
  54. #define REG0A_SUB_BRIGHT_B(val) (val)
  55. #define REG0A_PAIR BIT(6)
  56. #define REG0A_DE_SEL BIT(7)
  57. #define REG0B_MBK_POSITION(val) (val)
  58. #define REG0B_HD_FREERUN BIT(4)
  59. #define REG0B_VD_FREERUN BIT(5)
  60. #define REG0B_YUV2BIN(val) ((val) << 6)
  61. #define REG0C_CONTRAST_R(val) (val)
  62. #define REG0C_DOUBLEREAD BIT(7)
  63. #define REG0D_CONTRAST_G(val) (val)
  64. #define REG0D_RGB_YUV BIT(7)
  65. #define REG0E_CONTRAST_B(val) (val)
  66. #define REG0E_PIXELCOLORDRIVE BIT(7)
  67. #define REG0F_ASPECT BIT(0)
  68. #define REG0F_OVERSCAN(val) ((val) << 1)
  69. #define REG0F_FRAMEWIDTH(val) ((val) << 3)
  70. #define REG10_BRIGHT(val) (val)
  71. #define REG11_SIG_GAIN(val) (val)
  72. #define REG11_SIGC_CNTL BIT(6)
  73. #define REG11_SIGC_POL BIT(7)
  74. #define REG12_COLOR(val) (val)
  75. #define REG12_PWCKSEL(val) ((val) << 6)
  76. #define REG13_4096LEVEL_CNTL(val) (val)
  77. #define REG13_SL4096(val) ((val) << 4)
  78. #define REG13_LIMITER_CONTROL BIT(7)
  79. #define REG14_PANEL_TEST(val) (val)
  80. #define REG15_NVM_LINK0 BIT(0)
  81. #define REG15_NVM_LINK1 BIT(1)
  82. #define REG15_NVM_LINK2 BIT(2)
  83. #define REG15_NVM_LINK3 BIT(3)
  84. #define REG15_NVM_LINK4 BIT(4)
  85. #define REG15_NVM_LINK5 BIT(5)
  86. #define REG15_NVM_LINK6 BIT(6)
  87. #define REG15_NVM_LINK7 BIT(7)
  88. struct y030xx067a_info {
  89. const struct drm_display_mode *display_modes;
  90. unsigned int num_modes;
  91. u16 width_mm, height_mm;
  92. u32 bus_format, bus_flags;
  93. };
  94. struct y030xx067a {
  95. struct drm_panel panel;
  96. struct spi_device *spi;
  97. struct regmap *map;
  98. const struct y030xx067a_info *panel_info;
  99. struct regulator *supply;
  100. struct gpio_desc *reset_gpio;
  101. };
  102. static inline struct y030xx067a *to_y030xx067a(struct drm_panel *panel)
  103. {
  104. return container_of(panel, struct y030xx067a, panel);
  105. }
  106. static const struct reg_sequence y030xx067a_init_sequence[] = {
  107. { 0x00, REG00_VBRT_CTRL(0x7f) },
  108. { 0x01, REG01_COM_DC(0x3c) },
  109. { 0x02, REG02_VESA_SEL(0x3) | REG02_DA_CONTRAST(0x1f) },
  110. { 0x03, REG03_VPOSITION(0x0a) },
  111. { 0x04, REG04_HPOSITION1(0xd2) },
  112. { 0x05, REG05_CLIP | REG05_NVM_VREFRESH | REG05_SLBRCHARGE(0x2) },
  113. { 0x06, REG06_NT },
  114. { 0x07, 0 },
  115. { 0x08, REG08_PANEL(0x1) | REG08_CLOCK_DIV(0x2) },
  116. { 0x09, REG09_SUB_BRIGHT_R(0x20) },
  117. { 0x0a, REG0A_SUB_BRIGHT_B(0x20) },
  118. { 0x0b, REG0B_HD_FREERUN | REG0B_VD_FREERUN },
  119. { 0x0c, REG0C_CONTRAST_R(0x00) },
  120. { 0x0d, REG0D_CONTRAST_G(0x00) },
  121. { 0x0e, REG0E_CONTRAST_B(0x10) },
  122. { 0x0f, 0 },
  123. { 0x10, REG10_BRIGHT(0x7f) },
  124. { 0x11, REG11_SIGC_CNTL | REG11_SIG_GAIN(0x3f) },
  125. { 0x12, REG12_COLOR(0x20) | REG12_PWCKSEL(0x1) },
  126. { 0x13, REG13_4096LEVEL_CNTL(0x8) },
  127. { 0x14, 0 },
  128. { 0x15, 0 },
  129. };
  130. static int y030xx067a_prepare(struct drm_panel *panel)
  131. {
  132. struct y030xx067a *priv = to_y030xx067a(panel);
  133. struct device *dev = &priv->spi->dev;
  134. int err;
  135. err = regulator_enable(priv->supply);
  136. if (err) {
  137. dev_err(dev, "Failed to enable power supply: %d\n", err);
  138. return err;
  139. }
  140. /* Reset the chip */
  141. gpiod_set_value_cansleep(priv->reset_gpio, 1);
  142. usleep_range(1000, 20000);
  143. gpiod_set_value_cansleep(priv->reset_gpio, 0);
  144. usleep_range(1000, 20000);
  145. err = regmap_multi_reg_write(priv->map, y030xx067a_init_sequence,
  146. ARRAY_SIZE(y030xx067a_init_sequence));
  147. if (err) {
  148. dev_err(dev, "Failed to init registers: %d\n", err);
  149. goto err_disable_regulator;
  150. }
  151. return 0;
  152. err_disable_regulator:
  153. regulator_disable(priv->supply);
  154. return err;
  155. }
  156. static int y030xx067a_unprepare(struct drm_panel *panel)
  157. {
  158. struct y030xx067a *priv = to_y030xx067a(panel);
  159. gpiod_set_value_cansleep(priv->reset_gpio, 1);
  160. regulator_disable(priv->supply);
  161. return 0;
  162. }
  163. static int y030xx067a_enable(struct drm_panel *panel)
  164. {
  165. struct y030xx067a *priv = to_y030xx067a(panel);
  166. regmap_set_bits(priv->map, 0x06, REG06_XPSAVE);
  167. if (panel->backlight) {
  168. /* Wait for the picture to be ready before enabling backlight */
  169. msleep(120);
  170. }
  171. return 0;
  172. }
  173. static int y030xx067a_disable(struct drm_panel *panel)
  174. {
  175. struct y030xx067a *priv = to_y030xx067a(panel);
  176. regmap_clear_bits(priv->map, 0x06, REG06_XPSAVE);
  177. return 0;
  178. }
  179. static int y030xx067a_get_modes(struct drm_panel *panel,
  180. struct drm_connector *connector)
  181. {
  182. struct y030xx067a *priv = to_y030xx067a(panel);
  183. const struct y030xx067a_info *panel_info = priv->panel_info;
  184. struct drm_display_mode *mode;
  185. unsigned int i;
  186. for (i = 0; i < panel_info->num_modes; i++) {
  187. mode = drm_mode_duplicate(connector->dev,
  188. &panel_info->display_modes[i]);
  189. if (!mode)
  190. return -ENOMEM;
  191. drm_mode_set_name(mode);
  192. mode->type = DRM_MODE_TYPE_DRIVER;
  193. if (panel_info->num_modes == 1)
  194. mode->type |= DRM_MODE_TYPE_PREFERRED;
  195. drm_mode_probed_add(connector, mode);
  196. }
  197. connector->display_info.bpc = 8;
  198. connector->display_info.width_mm = panel_info->width_mm;
  199. connector->display_info.height_mm = panel_info->height_mm;
  200. drm_display_info_set_bus_formats(&connector->display_info,
  201. &panel_info->bus_format, 1);
  202. connector->display_info.bus_flags = panel_info->bus_flags;
  203. return panel_info->num_modes;
  204. }
  205. static const struct drm_panel_funcs y030xx067a_funcs = {
  206. .prepare = y030xx067a_prepare,
  207. .unprepare = y030xx067a_unprepare,
  208. .enable = y030xx067a_enable,
  209. .disable = y030xx067a_disable,
  210. .get_modes = y030xx067a_get_modes,
  211. };
  212. static const struct regmap_config y030xx067a_regmap_config = {
  213. .reg_bits = 8,
  214. .val_bits = 8,
  215. .max_register = 0x15,
  216. .cache_type = REGCACHE_FLAT,
  217. };
  218. static int y030xx067a_probe(struct spi_device *spi)
  219. {
  220. struct device *dev = &spi->dev;
  221. struct y030xx067a *priv;
  222. int err;
  223. priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
  224. if (!priv)
  225. return -ENOMEM;
  226. priv->spi = spi;
  227. spi_set_drvdata(spi, priv);
  228. priv->map = devm_regmap_init_spi(spi, &y030xx067a_regmap_config);
  229. if (IS_ERR(priv->map)) {
  230. dev_err(dev, "Unable to init regmap\n");
  231. return PTR_ERR(priv->map);
  232. }
  233. priv->panel_info = of_device_get_match_data(dev);
  234. if (!priv->panel_info)
  235. return -EINVAL;
  236. priv->supply = devm_regulator_get(dev, "power");
  237. if (IS_ERR(priv->supply))
  238. return dev_err_probe(dev, PTR_ERR(priv->supply),
  239. "Failed to get power supply\n");
  240. priv->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
  241. if (IS_ERR(priv->reset_gpio))
  242. return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
  243. "Failed to get reset GPIO\n");
  244. drm_panel_init(&priv->panel, dev, &y030xx067a_funcs,
  245. DRM_MODE_CONNECTOR_DPI);
  246. err = drm_panel_of_backlight(&priv->panel);
  247. if (err)
  248. return err;
  249. drm_panel_add(&priv->panel);
  250. return 0;
  251. }
  252. static void y030xx067a_remove(struct spi_device *spi)
  253. {
  254. struct y030xx067a *priv = spi_get_drvdata(spi);
  255. drm_panel_remove(&priv->panel);
  256. drm_panel_disable(&priv->panel);
  257. drm_panel_unprepare(&priv->panel);
  258. }
  259. static const struct drm_display_mode y030xx067a_modes[] = {
  260. { /* 60 Hz */
  261. .clock = 14400,
  262. .hdisplay = 320,
  263. .hsync_start = 320 + 10,
  264. .hsync_end = 320 + 10 + 37,
  265. .htotal = 320 + 10 + 37 + 33,
  266. .vdisplay = 480,
  267. .vsync_start = 480 + 84,
  268. .vsync_end = 480 + 84 + 20,
  269. .vtotal = 480 + 84 + 20 + 16,
  270. .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
  271. },
  272. { /* 50 Hz */
  273. .clock = 12000,
  274. .hdisplay = 320,
  275. .hsync_start = 320 + 10,
  276. .hsync_end = 320 + 10 + 37,
  277. .htotal = 320 + 10 + 37 + 33,
  278. .vdisplay = 480,
  279. .vsync_start = 480 + 84,
  280. .vsync_end = 480 + 84 + 20,
  281. .vtotal = 480 + 84 + 20 + 16,
  282. .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
  283. },
  284. };
  285. static const struct y030xx067a_info y030xx067a_info = {
  286. .display_modes = y030xx067a_modes,
  287. .num_modes = ARRAY_SIZE(y030xx067a_modes),
  288. .width_mm = 69,
  289. .height_mm = 51,
  290. .bus_format = MEDIA_BUS_FMT_RGB888_3X8_DELTA,
  291. .bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE | DRM_BUS_FLAG_DE_LOW,
  292. };
  293. static const struct of_device_id y030xx067a_of_match[] = {
  294. { .compatible = "abt,y030xx067a", .data = &y030xx067a_info },
  295. { /* sentinel */ }
  296. };
  297. MODULE_DEVICE_TABLE(of, y030xx067a_of_match);
  298. static struct spi_driver y030xx067a_driver = {
  299. .driver = {
  300. .name = "abt-y030xx067a",
  301. .of_match_table = y030xx067a_of_match,
  302. },
  303. .probe = y030xx067a_probe,
  304. .remove = y030xx067a_remove,
  305. };
  306. module_spi_driver(y030xx067a_driver);
  307. MODULE_AUTHOR("Paul Cercueil <[email protected]>");
  308. MODULE_AUTHOR("Christophe Branchereau <[email protected]>");
  309. MODULE_LICENSE("GPL v2");