panel-jdi-lt070me05000.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2016 InforceComputing
  4. * Author: Vinay Simha BN <simhavcs@gmail.com>
  5. *
  6. * Copyright (C) 2016 Linaro Ltd
  7. * Author: Sumit Semwal <sumit.semwal@linaro.org>
  8. *
  9. * From internet archives, the panel for Nexus 7 2nd Gen, 2013 model is a
  10. * JDI model LT070ME05000, and its data sheet is at:
  11. * http://panelone.net/en/7-0-inch/JDI_LT070ME05000_7.0_inch-datasheet
  12. */
  13. #include <linux/backlight.h>
  14. #include <linux/delay.h>
  15. #include <linux/gpio/consumer.h>
  16. #include <linux/module.h>
  17. #include <linux/of.h>
  18. #include <linux/regulator/consumer.h>
  19. #include <video/mipi_display.h>
  20. #include <drm/drm_crtc.h>
  21. #include <drm/drm_mipi_dsi.h>
  22. #include <drm/drm_modes.h>
  23. #include <drm/drm_panel.h>
  24. static const char * const regulator_names[] = {
  25. "vddp",
  26. "iovcc"
  27. };
  28. struct jdi_panel {
  29. struct drm_panel base;
  30. struct mipi_dsi_device *dsi;
  31. struct regulator_bulk_data supplies[ARRAY_SIZE(regulator_names)];
  32. struct gpio_desc *enable_gpio;
  33. struct gpio_desc *reset_gpio;
  34. struct gpio_desc *dcdc_en_gpio;
  35. struct backlight_device *backlight;
  36. bool prepared;
  37. bool enabled;
  38. const struct drm_display_mode *mode;
  39. };
  40. static inline struct jdi_panel *to_jdi_panel(struct drm_panel *panel)
  41. {
  42. return container_of(panel, struct jdi_panel, base);
  43. }
  44. static int jdi_panel_init(struct jdi_panel *jdi)
  45. {
  46. struct mipi_dsi_device *dsi = jdi->dsi;
  47. struct device *dev = &jdi->dsi->dev;
  48. int ret;
  49. dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  50. ret = mipi_dsi_dcs_soft_reset(dsi);
  51. if (ret < 0)
  52. return ret;
  53. usleep_range(10000, 20000);
  54. ret = mipi_dsi_dcs_set_pixel_format(dsi, MIPI_DCS_PIXEL_FMT_24BIT << 4);
  55. if (ret < 0) {
  56. dev_err(dev, "failed to set pixel format: %d\n", ret);
  57. return ret;
  58. }
  59. ret = mipi_dsi_dcs_set_column_address(dsi, 0, jdi->mode->hdisplay - 1);
  60. if (ret < 0) {
  61. dev_err(dev, "failed to set column address: %d\n", ret);
  62. return ret;
  63. }
  64. ret = mipi_dsi_dcs_set_page_address(dsi, 0, jdi->mode->vdisplay - 1);
  65. if (ret < 0) {
  66. dev_err(dev, "failed to set page address: %d\n", ret);
  67. return ret;
  68. }
  69. /*
  70. * BIT(5) BCTRL = 1 Backlight Control Block On, Brightness registers
  71. * are active
  72. * BIT(3) BL = 1 Backlight Control On
  73. * BIT(2) DD = 0 Display Dimming is Off
  74. */
  75. ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_CONTROL_DISPLAY,
  76. (u8[]){ 0x24 }, 1);
  77. if (ret < 0) {
  78. dev_err(dev, "failed to write control display: %d\n", ret);
  79. return ret;
  80. }
  81. /* CABC off */
  82. ret = mipi_dsi_dcs_write(dsi, MIPI_DCS_WRITE_POWER_SAVE,
  83. (u8[]){ 0x00 }, 1);
  84. if (ret < 0) {
  85. dev_err(dev, "failed to set cabc off: %d\n", ret);
  86. return ret;
  87. }
  88. ret = mipi_dsi_dcs_exit_sleep_mode(dsi);
  89. if (ret < 0) {
  90. dev_err(dev, "failed to set exit sleep mode: %d\n", ret);
  91. return ret;
  92. }
  93. msleep(120);
  94. ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x00}, 2);
  95. if (ret < 0) {
  96. dev_err(dev, "failed to set mcap: %d\n", ret);
  97. return ret;
  98. }
  99. mdelay(10);
  100. /* Interface setting, video mode */
  101. ret = mipi_dsi_generic_write(dsi, (u8[])
  102. {0xB3, 0x26, 0x08, 0x00, 0x20, 0x00}, 6);
  103. if (ret < 0) {
  104. dev_err(dev, "failed to set display interface setting: %d\n"
  105. , ret);
  106. return ret;
  107. }
  108. mdelay(20);
  109. ret = mipi_dsi_generic_write(dsi, (u8[]){0xB0, 0x03}, 2);
  110. if (ret < 0) {
  111. dev_err(dev, "failed to set default values for mcap: %d\n"
  112. , ret);
  113. return ret;
  114. }
  115. return 0;
  116. }
  117. static int jdi_panel_on(struct jdi_panel *jdi)
  118. {
  119. struct mipi_dsi_device *dsi = jdi->dsi;
  120. struct device *dev = &jdi->dsi->dev;
  121. int ret;
  122. dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  123. ret = mipi_dsi_dcs_set_display_on(dsi);
  124. if (ret < 0)
  125. dev_err(dev, "failed to set display on: %d\n", ret);
  126. return ret;
  127. }
  128. static void jdi_panel_off(struct jdi_panel *jdi)
  129. {
  130. struct mipi_dsi_device *dsi = jdi->dsi;
  131. struct device *dev = &jdi->dsi->dev;
  132. int ret;
  133. dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
  134. ret = mipi_dsi_dcs_set_display_off(dsi);
  135. if (ret < 0)
  136. dev_err(dev, "failed to set display off: %d\n", ret);
  137. ret = mipi_dsi_dcs_enter_sleep_mode(dsi);
  138. if (ret < 0)
  139. dev_err(dev, "failed to enter sleep mode: %d\n", ret);
  140. msleep(100);
  141. }
  142. static int jdi_panel_disable(struct drm_panel *panel)
  143. {
  144. struct jdi_panel *jdi = to_jdi_panel(panel);
  145. if (!jdi->enabled)
  146. return 0;
  147. backlight_disable(jdi->backlight);
  148. jdi->enabled = false;
  149. return 0;
  150. }
  151. static int jdi_panel_unprepare(struct drm_panel *panel)
  152. {
  153. struct jdi_panel *jdi = to_jdi_panel(panel);
  154. struct device *dev = &jdi->dsi->dev;
  155. int ret;
  156. if (!jdi->prepared)
  157. return 0;
  158. jdi_panel_off(jdi);
  159. ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
  160. if (ret < 0)
  161. dev_err(dev, "regulator disable failed, %d\n", ret);
  162. gpiod_set_value(jdi->enable_gpio, 0);
  163. gpiod_set_value(jdi->reset_gpio, 1);
  164. gpiod_set_value(jdi->dcdc_en_gpio, 0);
  165. jdi->prepared = false;
  166. return 0;
  167. }
  168. static int jdi_panel_prepare(struct drm_panel *panel)
  169. {
  170. struct jdi_panel *jdi = to_jdi_panel(panel);
  171. struct device *dev = &jdi->dsi->dev;
  172. int ret;
  173. if (jdi->prepared)
  174. return 0;
  175. ret = regulator_bulk_enable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
  176. if (ret < 0) {
  177. dev_err(dev, "regulator enable failed, %d\n", ret);
  178. return ret;
  179. }
  180. msleep(20);
  181. gpiod_set_value(jdi->dcdc_en_gpio, 1);
  182. usleep_range(10, 20);
  183. gpiod_set_value(jdi->reset_gpio, 0);
  184. usleep_range(10, 20);
  185. gpiod_set_value(jdi->enable_gpio, 1);
  186. usleep_range(10, 20);
  187. ret = jdi_panel_init(jdi);
  188. if (ret < 0) {
  189. dev_err(dev, "failed to init panel: %d\n", ret);
  190. goto poweroff;
  191. }
  192. ret = jdi_panel_on(jdi);
  193. if (ret < 0) {
  194. dev_err(dev, "failed to set panel on: %d\n", ret);
  195. goto poweroff;
  196. }
  197. jdi->prepared = true;
  198. return 0;
  199. poweroff:
  200. ret = regulator_bulk_disable(ARRAY_SIZE(jdi->supplies), jdi->supplies);
  201. if (ret < 0)
  202. dev_err(dev, "regulator disable failed, %d\n", ret);
  203. gpiod_set_value(jdi->enable_gpio, 0);
  204. gpiod_set_value(jdi->reset_gpio, 1);
  205. gpiod_set_value(jdi->dcdc_en_gpio, 0);
  206. return ret;
  207. }
  208. static int jdi_panel_enable(struct drm_panel *panel)
  209. {
  210. struct jdi_panel *jdi = to_jdi_panel(panel);
  211. if (jdi->enabled)
  212. return 0;
  213. backlight_enable(jdi->backlight);
  214. jdi->enabled = true;
  215. return 0;
  216. }
  217. static const struct drm_display_mode default_mode = {
  218. .clock = 155493,
  219. .hdisplay = 1200,
  220. .hsync_start = 1200 + 48,
  221. .hsync_end = 1200 + 48 + 32,
  222. .htotal = 1200 + 48 + 32 + 60,
  223. .vdisplay = 1920,
  224. .vsync_start = 1920 + 3,
  225. .vsync_end = 1920 + 3 + 5,
  226. .vtotal = 1920 + 3 + 5 + 6,
  227. .flags = 0,
  228. };
  229. static int jdi_panel_get_modes(struct drm_panel *panel,
  230. struct drm_connector *connector)
  231. {
  232. struct drm_display_mode *mode;
  233. struct jdi_panel *jdi = to_jdi_panel(panel);
  234. struct device *dev = &jdi->dsi->dev;
  235. mode = drm_mode_duplicate(connector->dev, &default_mode);
  236. if (!mode) {
  237. dev_err(dev, "failed to add mode %ux%ux@%u\n",
  238. default_mode.hdisplay, default_mode.vdisplay,
  239. drm_mode_vrefresh(&default_mode));
  240. return -ENOMEM;
  241. }
  242. drm_mode_set_name(mode);
  243. drm_mode_probed_add(connector, mode);
  244. connector->display_info.width_mm = 95;
  245. connector->display_info.height_mm = 151;
  246. return 1;
  247. }
  248. static int dsi_dcs_bl_get_brightness(struct backlight_device *bl)
  249. {
  250. struct mipi_dsi_device *dsi = bl_get_data(bl);
  251. int ret;
  252. u16 brightness = bl->props.brightness;
  253. dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
  254. ret = mipi_dsi_dcs_get_display_brightness(dsi, &brightness);
  255. if (ret < 0)
  256. return ret;
  257. dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  258. return brightness & 0xff;
  259. }
  260. static int dsi_dcs_bl_update_status(struct backlight_device *bl)
  261. {
  262. struct mipi_dsi_device *dsi = bl_get_data(bl);
  263. int ret;
  264. dsi->mode_flags &= ~MIPI_DSI_MODE_LPM;
  265. ret = mipi_dsi_dcs_set_display_brightness(dsi, bl->props.brightness);
  266. if (ret < 0)
  267. return ret;
  268. dsi->mode_flags |= MIPI_DSI_MODE_LPM;
  269. return 0;
  270. }
  271. static const struct backlight_ops dsi_bl_ops = {
  272. .update_status = dsi_dcs_bl_update_status,
  273. .get_brightness = dsi_dcs_bl_get_brightness,
  274. };
  275. static struct backlight_device *
  276. drm_panel_create_dsi_backlight(struct mipi_dsi_device *dsi)
  277. {
  278. struct device *dev = &dsi->dev;
  279. struct backlight_properties props;
  280. memset(&props, 0, sizeof(props));
  281. props.type = BACKLIGHT_RAW;
  282. props.brightness = 255;
  283. props.max_brightness = 255;
  284. return devm_backlight_device_register(dev, dev_name(dev), dev, dsi,
  285. &dsi_bl_ops, &props);
  286. }
  287. static const struct drm_panel_funcs jdi_panel_funcs = {
  288. .disable = jdi_panel_disable,
  289. .unprepare = jdi_panel_unprepare,
  290. .prepare = jdi_panel_prepare,
  291. .enable = jdi_panel_enable,
  292. .get_modes = jdi_panel_get_modes,
  293. };
  294. static const struct of_device_id jdi_of_match[] = {
  295. { .compatible = "jdi,lt070me05000", },
  296. { }
  297. };
  298. MODULE_DEVICE_TABLE(of, jdi_of_match);
  299. static int jdi_panel_add(struct jdi_panel *jdi)
  300. {
  301. struct device *dev = &jdi->dsi->dev;
  302. int ret;
  303. unsigned int i;
  304. jdi->mode = &default_mode;
  305. for (i = 0; i < ARRAY_SIZE(jdi->supplies); i++)
  306. jdi->supplies[i].supply = regulator_names[i];
  307. ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(jdi->supplies),
  308. jdi->supplies);
  309. if (ret < 0) {
  310. dev_err(dev, "failed to init regulator, ret=%d\n", ret);
  311. return ret;
  312. }
  313. jdi->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_LOW);
  314. if (IS_ERR(jdi->enable_gpio)) {
  315. ret = PTR_ERR(jdi->enable_gpio);
  316. dev_err(dev, "cannot get enable-gpio %d\n", ret);
  317. return ret;
  318. }
  319. jdi->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
  320. if (IS_ERR(jdi->reset_gpio)) {
  321. ret = PTR_ERR(jdi->reset_gpio);
  322. dev_err(dev, "cannot get reset-gpios %d\n", ret);
  323. return ret;
  324. }
  325. jdi->dcdc_en_gpio = devm_gpiod_get(dev, "dcdc-en", GPIOD_OUT_LOW);
  326. if (IS_ERR(jdi->dcdc_en_gpio)) {
  327. ret = PTR_ERR(jdi->dcdc_en_gpio);
  328. dev_err(dev, "cannot get dcdc-en-gpio %d\n", ret);
  329. return ret;
  330. }
  331. jdi->backlight = drm_panel_create_dsi_backlight(jdi->dsi);
  332. if (IS_ERR(jdi->backlight)) {
  333. ret = PTR_ERR(jdi->backlight);
  334. dev_err(dev, "failed to register backlight %d\n", ret);
  335. return ret;
  336. }
  337. drm_panel_init(&jdi->base, &jdi->dsi->dev, &jdi_panel_funcs,
  338. DRM_MODE_CONNECTOR_DSI);
  339. drm_panel_add(&jdi->base);
  340. return 0;
  341. }
  342. static void jdi_panel_del(struct jdi_panel *jdi)
  343. {
  344. if (jdi->base.dev)
  345. drm_panel_remove(&jdi->base);
  346. }
  347. static int jdi_panel_probe(struct mipi_dsi_device *dsi)
  348. {
  349. struct jdi_panel *jdi;
  350. int ret;
  351. dsi->lanes = 4;
  352. dsi->format = MIPI_DSI_FMT_RGB888;
  353. dsi->mode_flags = MIPI_DSI_MODE_VIDEO_HSE | MIPI_DSI_MODE_VIDEO |
  354. MIPI_DSI_CLOCK_NON_CONTINUOUS;
  355. jdi = devm_kzalloc(&dsi->dev, sizeof(*jdi), GFP_KERNEL);
  356. if (!jdi)
  357. return -ENOMEM;
  358. mipi_dsi_set_drvdata(dsi, jdi);
  359. jdi->dsi = dsi;
  360. ret = jdi_panel_add(jdi);
  361. if (ret < 0)
  362. return ret;
  363. return mipi_dsi_attach(dsi);
  364. }
  365. static int jdi_panel_remove(struct mipi_dsi_device *dsi)
  366. {
  367. struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
  368. int ret;
  369. ret = jdi_panel_disable(&jdi->base);
  370. if (ret < 0)
  371. dev_err(&dsi->dev, "failed to disable panel: %d\n", ret);
  372. ret = mipi_dsi_detach(dsi);
  373. if (ret < 0)
  374. dev_err(&dsi->dev, "failed to detach from DSI host: %d\n",
  375. ret);
  376. jdi_panel_del(jdi);
  377. return 0;
  378. }
  379. static void jdi_panel_shutdown(struct mipi_dsi_device *dsi)
  380. {
  381. struct jdi_panel *jdi = mipi_dsi_get_drvdata(dsi);
  382. jdi_panel_disable(&jdi->base);
  383. }
  384. static struct mipi_dsi_driver jdi_panel_driver = {
  385. .driver = {
  386. .name = "panel-jdi-lt070me05000",
  387. .of_match_table = jdi_of_match,
  388. },
  389. .probe = jdi_panel_probe,
  390. .remove = jdi_panel_remove,
  391. .shutdown = jdi_panel_shutdown,
  392. };
  393. module_mipi_dsi_driver(jdi_panel_driver);
  394. MODULE_AUTHOR("Sumit Semwal <sumit.semwal@linaro.org>");
  395. MODULE_AUTHOR("Vinay Simha BN <simhavcs@gmail.com>");
  396. MODULE_DESCRIPTION("JDI LT070ME05000 WUXGA");
  397. MODULE_LICENSE("GPL v2");