panel-sharp-ls043t1le01.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. /*
  2. * Copyright (C) 2015 Red Hat
  3. * Copyright (C) 2015 Sony Mobile Communications Inc.
  4. * Author: Werner Johansson <werner.johansson@sonymobile.com>
  5. *
  6. * Based on AUO panel driver by Rob Clark <robdclark@gmail.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License version 2 as published by
  10. * the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but WITHOUT
  13. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  14. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  15. * more details.
  16. *
  17. * You should have received a copy of the GNU General Public License along with
  18. * this program. If not, see <http://www.gnu.org/licenses/>.
  19. */
  20. #include <linux/backlight.h>
  21. #include <linux/gpio/consumer.h>
  22. #include <linux/module.h>
  23. #include <linux/of.h>
  24. #include <linux/regulator/consumer.h>
  25. #include <drm/drmP.h>
  26. #include <drm/drm_crtc.h>
  27. #include <drm/drm_mipi_dsi.h>
  28. #include <drm/drm_panel.h>
  29. #include <video/mipi_display.h>
  30. struct sharp_nt_panel {
  31. struct drm_panel base;
  32. struct mipi_dsi_device *dsi;
  33. struct backlight_device *backlight;
  34. struct regulator *supply;
  35. struct gpio_desc *reset_gpio;
  36. bool prepared;
  37. bool enabled;
  38. const struct drm_display_mode *mode;
  39. };
  40. static inline struct sharp_nt_panel *to_sharp_nt_panel(struct drm_panel *panel)
  41. {
  42. return container_of(panel, struct sharp_nt_panel, base);
  43. }
  44. static int sharp_nt_panel_init(struct sharp_nt_panel *sharp_nt)
  45. {
  46. struct mipi_dsi_device *dsi = sharp_nt->dsi;
  47. int ret;
  48. dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  49. ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
  50. if (ret < 0)
  51. return ret;
  52. msleep(120);
  53. /* Novatek two-lane operation */
  54. ret = mipi_dsi_dcs_write(dsi, 0xae, (u8[]){ 0x03 }, 1);
  55. if (ret < 0)
  56. return ret;
  57. /* Set both MCU and RGB I/F to 24bpp */
  58. ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT |
  59. (MIPI_DCS_PIXEL_FMT_24BIT << 4));
  60. if (ret < 0)
  61. return ret;
  62. return 0;
  63. }
  64. static int sharp_nt_panel_on(struct sharp_nt_panel *sharp_nt)
  65. {
  66. struct mipi_dsi_device *dsi = sharp_nt->dsi;
  67. int ret;
  68. dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  69. ret = mipi_dsi_dcs_set_display_on(dsi);
  70. if (ret < 0)
  71. return ret;
  72. return 0;
  73. }
  74. static int sharp_nt_panel_off(struct sharp_nt_panel *sharp_nt)
  75. {
  76. struct mipi_dsi_device *dsi = sharp_nt->dsi;
  77. int ret;
  78. dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
  79. ret = mipi_dsi_dcs_set_display_off(dsi);
  80. if (ret < 0)
  81. return ret;
  82. ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
  83. if (ret < 0)
  84. return ret;
  85. return 0;
  86. }
  87. static int sharp_nt_panel_disable(struct drm_panel *panel)
  88. {
  89. struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
  90. if (!sharp_nt->enabled)
  91. return 0;
  92. if (sharp_nt->backlight) {
  93. sharp_nt->backlight->props.power = FB_BLANK_POWERDOWN;
  94. backlight_update_status(sharp_nt->backlight);
  95. }
  96. sharp_nt->enabled = false;
  97. return 0;
  98. }
  99. static int sharp_nt_panel_unprepare(struct drm_panel *panel)
  100. {
  101. struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
  102. int ret;
  103. if (!sharp_nt->prepared)
  104. return 0;
  105. ret = sharp_nt_panel_off(sharp_nt);
  106. if (ret < 0) {
  107. dev_err(panel->dev, "failed to set panel off: %d\n", ret);
  108. return ret;
  109. }
  110. regulator_disable(sharp_nt->supply);
  111. if (sharp_nt->reset_gpio)
  112. gpiod_set_value(sharp_nt->reset_gpio, 0);
  113. sharp_nt->prepared = false;
  114. return 0;
  115. }
  116. static int sharp_nt_panel_prepare(struct drm_panel *panel)
  117. {
  118. struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
  119. int ret;
  120. if (sharp_nt->prepared)
  121. return 0;
  122. ret = regulator_enable(sharp_nt->supply);
  123. if (ret < 0)
  124. return ret;
  125. msleep(20);
  126. if (sharp_nt->reset_gpio) {
  127. gpiod_set_value(sharp_nt->reset_gpio, 1);
  128. msleep(1);
  129. gpiod_set_value(sharp_nt->reset_gpio, 0);
  130. msleep(1);
  131. gpiod_set_value(sharp_nt->reset_gpio, 1);
  132. msleep(10);
  133. }
  134. ret = sharp_nt_panel_init(sharp_nt);
  135. if (ret < 0) {
  136. dev_err(panel->dev, "failed to init panel: %d\n", ret);
  137. goto poweroff;
  138. }
  139. ret = sharp_nt_panel_on(sharp_nt);
  140. if (ret < 0) {
  141. dev_err(panel->dev, "failed to set panel on: %d\n", ret);
  142. goto poweroff;
  143. }
  144. sharp_nt->prepared = true;
  145. return 0;
  146. poweroff:
  147. regulator_disable(sharp_nt->supply);
  148. if (sharp_nt->reset_gpio)
  149. gpiod_set_value(sharp_nt->reset_gpio, 0);
  150. return ret;
  151. }
  152. static int sharp_nt_panel_enable(struct drm_panel *panel)
  153. {
  154. struct sharp_nt_panel *sharp_nt = to_sharp_nt_panel(panel);
  155. if (sharp_nt->enabled)
  156. return 0;
  157. if (sharp_nt->backlight) {
  158. sharp_nt->backlight->props.power = FB_BLANK_UNBLANK;
  159. backlight_update_status(sharp_nt->backlight);
  160. }
  161. sharp_nt->enabled = true;
  162. return 0;
  163. }
  164. static const struct drm_display_mode default_mode = {
  165. .clock = 41118,
  166. .hdisplay = 540,
  167. .hsync_start = 540 + 48,
  168. .hsync_end = 540 + 48 + 80,
  169. .htotal = 540 + 48 + 80 + 32,
  170. .vdisplay = 960,
  171. .vsync_start = 960 + 3,
  172. .vsync_end = 960 + 3 + 15,
  173. .vtotal = 960 + 3 + 15 + 1,
  174. .vrefresh = 60,
  175. };
  176. static int sharp_nt_panel_get_modes(struct drm_panel *panel)
  177. {
  178. struct drm_display_mode *mode;
  179. mode = drm_mode_duplicate(panel->drm, &default_mode);
  180. if (!mode) {
  181. dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
  182. default_mode.hdisplay, default_mode.vdisplay,
  183. default_mode.vrefresh);
  184. return -ENOMEM;
  185. }
  186. drm_mode_set_name(mode);
  187. drm_mode_probed_add(panel->connector, mode);
  188. panel->connector->display_info.width_mm = 54;
  189. panel->connector->display_info.height_mm = 95;
  190. return 1;
  191. }
  192. static const struct drm_panel_funcs sharp_nt_panel_funcs = {
  193. .disable = sharp_nt_panel_disable,
  194. .unprepare = sharp_nt_panel_unprepare,
  195. .prepare = sharp_nt_panel_prepare,
  196. .enable = sharp_nt_panel_enable,
  197. .get_modes = sharp_nt_panel_get_modes,
  198. };
  199. static int sharp_nt_panel_add(struct sharp_nt_panel *sharp_nt)
  200. {
  201. struct device *dev = &sharp_nt->dsi->dev;
  202. struct device_node *np;
  203. int ret;
  204. sharp_nt->mode = &default_mode;
  205. sharp_nt->supply = devm_regulator_get(dev, "avdd");
  206. if (IS_ERR(sharp_nt->supply))
  207. return PTR_ERR(sharp_nt->supply);
  208. sharp_nt->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
  209. if (IS_ERR(sharp_nt->reset_gpio)) {
  210. dev_err(dev, "cannot get reset-gpios %ld\n",
  211. PTR_ERR(sharp_nt->reset_gpio));
  212. sharp_nt->reset_gpio = NULL;
  213. } else {
  214. gpiod_set_value(sharp_nt->reset_gpio, 0);
  215. }
  216. np = of_parse_phandle(dev->of_node, "backlight", 0);
  217. if (np) {
  218. sharp_nt->backlight = of_find_backlight_by_node(np);
  219. of_node_put(np);
  220. if (!sharp_nt->backlight)
  221. return -EPROBE_DEFER;
  222. }
  223. drm_panel_init(&sharp_nt->base);
  224. sharp_nt->base.funcs = &sharp_nt_panel_funcs;
  225. sharp_nt->base.dev = &sharp_nt->dsi->dev;
  226. ret = drm_panel_add(&sharp_nt->base);
  227. if (ret < 0)
  228. goto put_backlight;
  229. return 0;
  230. put_backlight:
  231. if (sharp_nt->backlight)
  232. put_device(&sharp_nt->backlight->dev);
  233. return ret;
  234. }
  235. static void sharp_nt_panel_del(struct sharp_nt_panel *sharp_nt)
  236. {
  237. if (sharp_nt->base.dev)
  238. drm_panel_remove(&sharp_nt->base);
  239. if (sharp_nt->backlight)
  240. put_device(&sharp_nt->backlight->dev);
  241. }
  242. static int sharp_nt_panel_probe(struct mipi_dsi_device *dsi)
  243. {
  244. struct sharp_nt_panel *sharp_nt;
  245. int ret;
  246. dsi->lanes = 2;
  247. dsi->format = MIPI_DSI_FMT_RGB888;
  248. dsi->mode_flags = MIPI_DSI_MODE_VIDEO |
  249. MIPI_DSI_MODE_VIDEO_HSE |
  250. MIPI_DSI_CLOCK_NON_CONTINUOUS |
  251. MIPI_DSI_MODE_EOT_PACKET;
  252. sharp_nt = devm_kzalloc(&dsi->dev, sizeof(*sharp_nt), GFP_KERNEL);
  253. if (!sharp_nt)
  254. return -ENOMEM;
  255. mipi_dsi_set_drvdata(dsi, sharp_nt);
  256. sharp_nt->dsi = dsi;
  257. ret = sharp_nt_panel_add(sharp_nt);
  258. if (ret < 0)
  259. return ret;
  260. return mipi_dsi_attach(dsi);
  261. }
  262. static int sharp_nt_panel_remove(struct mipi_dsi_device *dsi)
  263. {
  264. struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
  265. int ret;
  266. ret = sharp_nt_panel_disable(&sharp_nt->base);
  267. if (ret < 0)
  268. dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
  269. ret = mipi_dsi_detach(dsi);
  270. if (ret < 0)
  271. dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", ret);
  272. drm_panel_detach(&sharp_nt->base);
  273. sharp_nt_panel_del(sharp_nt);
  274. return 0;
  275. }
  276. static void sharp_nt_panel_shutdown(struct mipi_dsi_device *dsi)
  277. {
  278. struct sharp_nt_panel *sharp_nt = mipi_dsi_get_drvdata(dsi);
  279. sharp_nt_panel_disable(&sharp_nt->base);
  280. }
  281. static const struct of_device_id sharp_nt_of_match[] = {
  282. { .compatible = "sharp,ls043t1le01-qhd", },
  283. { }
  284. };
  285. MODULE_DEVICE_TABLE(of, sharp_nt_of_match);
  286. static struct mipi_dsi_driver sharp_nt_panel_driver = {
  287. .driver = {
  288. .name = "panel-sharp-ls043t1le01-qhd",
  289. .of_match_table = sharp_nt_of_match,
  290. },
  291. .probe = sharp_nt_panel_probe,
  292. .remove = sharp_nt_panel_remove,
  293. .shutdown = sharp_nt_panel_shutdown,
  294. };
  295. module_mipi_dsi_driver(sharp_nt_panel_driver);
  296. MODULE_AUTHOR("Werner Johansson <werner.johansson@sonymobile.com>");
  297. MODULE_DESCRIPTION("Sharp LS043T1LE01 NT35565-based qHD (540x960) video mode panel driver");
  298. MODULE_LICENSE("GPL v2");