Advertisement
Guest User

Untitled

a guest
Jan 29th, 2020
353
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.58 KB | None | 0 0
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * This file based on panel-ilitek-ili9881c.c
  4. */
  5.  
  6. #include <linux/backlight.h>
  7. #include <linux/delay.h>
  8. #include <linux/device.h>
  9. #include <linux/err.h>
  10. #include <linux/errno.h>
  11. #include <linux/fb.h>
  12. #include <linux/kernel.h>
  13. #include <linux/media-bus-format.h>
  14. #include <linux/module.h>
  15.  
  16. #include <linux/gpio/consumer.h>
  17. #include <linux/regulator/consumer.h>
  18.  
  19. #include <drm/drm_connector.h>
  20. #include <drm/drm_mipi_dsi.h>
  21. #include <drm/drm_modes.h>
  22. #include <drm/drm_panel.h>
  23. #include <drm/drm_print.h>
  24.  
  25. enum ili9881c_op {
  26. ILI9881C_SWITCH_PAGE,
  27. ILI9881C_COMMAND,
  28. };
  29.  
  30. struct ili9881c_instr {
  31. enum ili9881c_op op;
  32.  
  33. union arg {
  34. struct cmd {
  35. u8 cmd;
  36. u8 data;
  37. } cmd;
  38. u8 page;
  39. } arg;
  40. };
  41.  
  42. #define ILI9881C_SWITCH_PAGE_INSTR(_page) \
  43. { \
  44. .op = ILI9881C_SWITCH_PAGE, \
  45. .arg = { \
  46. .page = (_page), \
  47. }, \
  48. }
  49.  
  50. #define ILI9881C_COMMAND_INSTR(_cmd, _data) \
  51. { \
  52. .op = ILI9881C_COMMAND, \
  53. .arg = { \
  54. .cmd = { \
  55. .cmd = (_cmd), \
  56. .data = (_data), \
  57. }, \
  58. }, \
  59. }
  60.  
  61. static const struct ili9881c_instr ili9881c_init[] = {
  62. ILI9881C_COMMAND_INSTR(0xB2, 0x50),
  63. ILI9881C_COMMAND_INSTR(0x80, 0x8B),
  64. ILI9881C_COMMAND_INSTR(0x81, 0x78),
  65. ILI9881C_COMMAND_INSTR(0x82, 0x84),
  66. ILI9881C_COMMAND_INSTR(0x83, 0x88),
  67. ILI9881C_COMMAND_INSTR(0x84, 0xA8),
  68. ILI9881C_COMMAND_INSTR(0x85, 0xE3),
  69. ILI9881C_COMMAND_INSTR(0x86, 0x88)
  70. };
  71.  
  72. /*
  73. * The panel seems to accept some private DCS commands that map
  74. * directly to registers.
  75. *
  76. * It is organised by page, with each page having its own set of
  77. * registers, and the first page looks like it's holding the standard
  78. * DCS commands.
  79. *
  80. * So before any attempt at sending a command or data, we have to be
  81. * sure if we're in the right page or not.
  82. */
  83. static int ili9881c_switch_page(struct ili9881c *ctx, u8 page)
  84. {
  85. u8 buf[4] = { 0xff, 0x98, 0x81, page };
  86. int ret;
  87.  
  88. ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
  89. if (ret < 0)
  90. return ret;
  91.  
  92. return 0;
  93. }
  94.  
  95. static int ili9881c_send_cmd_data(struct ili9881c *ctx, u8 cmd, u8 data)
  96. {
  97. u8 buf[2] = { cmd, data };
  98. int ret;
  99.  
  100. ret = mipi_dsi_dcs_write_buffer(ctx->dsi, buf, sizeof(buf));
  101. if (ret < 0)
  102. return ret;
  103.  
  104. return 0;
  105. }
  106.  
  107. struct rb070d30_panel {
  108. struct drm_panel panel;
  109. struct mipi_dsi_device *dsi;
  110. //struct backlight_device *backlight;
  111. //struct regulator *supply;
  112.  
  113. struct {
  114. //struct gpio_desc *power;
  115. struct gpio_desc *reset;
  116. //struct gpio_desc *updn;
  117. //struct gpio_desc *shlr;
  118. } gpios;
  119. };
  120.  
  121. static inline struct rb070d30_panel *panel_to_rb070d30_panel(struct drm_panel *panel)
  122. {
  123. return container_of(panel, struct rb070d30_panel, panel);
  124. }
  125.  
  126. static int rb070d30_panel_prepare(struct drm_panel *panel)
  127. {
  128. struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
  129. int ret;
  130.  
  131. /*
  132. ret = regulator_enable(ctx->supply);
  133. if (ret < 0) {
  134. DRM_DEV_ERROR(&ctx->dsi->dev, "Failed to enable supply: %d\n", ret);
  135. return ret;
  136. }
  137. */
  138.  
  139. //msleep(20);
  140. //gpiod_set_value(ctx->gpios.power, 1);
  141. msleep(20);
  142. gpiod_set_value(ctx->gpios.reset, 0);
  143. msleep(20);
  144. gpiod_set_value(ctx->gpios.reset, 1);
  145. msleep(20);
  146.  
  147.  
  148.  
  149. for (i = 0; i < ARRAY_SIZE(ili9881c_init); i++) {
  150. const struct ili9881c_instr *instr = &ili9881c_init[i];
  151.  
  152. if (instr->op == ILI9881C_SWITCH_PAGE)
  153. ret = ili9881c_switch_page(ctx, instr->arg.page);
  154. else if (instr->op == ILI9881C_COMMAND)
  155. ret = ili9881c_send_cmd_data(ctx, instr->arg.cmd.cmd,
  156. instr->arg.cmd.data);
  157.  
  158. if (ret)
  159. return ret;
  160. }
  161.  
  162.  
  163.  
  164.  
  165. return 0;
  166. }
  167.  
  168. static int rb070d30_panel_unprepare(struct drm_panel *panel)
  169. {
  170. struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
  171.  
  172. gpiod_set_value(ctx->gpios.reset, 0);
  173. //gpiod_set_value(ctx->gpios.power, 0);
  174. //regulator_disable(ctx->supply);
  175.  
  176. return 0;
  177. }
  178.  
  179. static int rb070d30_panel_enable(struct drm_panel *panel)
  180. {
  181. struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
  182. int ret;
  183.  
  184. ret = mipi_dsi_dcs_exit_sleep_mode(ctx->dsi);
  185. if (ret)
  186. return ret;
  187.  
  188. /*
  189. ret = backlight_enable(ctx->backlight);
  190. if (ret)
  191. goto out;
  192. */
  193.  
  194. return 0;
  195.  
  196. //out:
  197. //mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
  198. //return ret;
  199. }
  200.  
  201. static int rb070d30_panel_disable(struct drm_panel *panel)
  202. {
  203. struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
  204.  
  205. //backlight_disable(ctx->backlight);
  206. return mipi_dsi_dcs_enter_sleep_mode(ctx->dsi);
  207. }
  208.  
  209. /* Default timings */
  210. static const struct drm_display_mode default_mode = {
  211. .clock = 51206,
  212. .hdisplay = 1024,
  213. .hsync_start = 1024 + 160,
  214. .hsync_end = 1024 + 160 + 80,
  215. .htotal = 1024 + 160 + 80 + 80,
  216. .vdisplay = 600,
  217. .vsync_start = 600 + 12,
  218. .vsync_end = 600 + 12 + 10,
  219. .vtotal = 600 + 12 + 10 + 13,
  220. .vrefresh = 60,
  221.  
  222. .width_mm = 154,
  223. .height_mm = 85,
  224. };
  225.  
  226. static int rb070d30_panel_get_modes(struct drm_panel *panel)
  227. {
  228. struct drm_connector *connector = panel->connector;
  229. struct rb070d30_panel *ctx = panel_to_rb070d30_panel(panel);
  230. struct drm_display_mode *mode;
  231. static const u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
  232.  
  233. mode = drm_mode_duplicate(panel->drm, &default_mode);
  234. if (!mode) {
  235. DRM_DEV_ERROR(&ctx->dsi->dev,
  236. "Failed to add mode " DRM_MODE_FMT "\n",
  237. DRM_MODE_ARG(&default_mode));
  238. return -EINVAL;
  239. }
  240.  
  241. drm_mode_set_name(mode);
  242.  
  243. mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
  244. drm_mode_probed_add(connector, mode);
  245.  
  246. panel->connector->display_info.bpc = 8;
  247. panel->connector->display_info.width_mm = mode->width_mm;
  248. panel->connector->display_info.height_mm = mode->height_mm;
  249. drm_display_info_set_bus_formats(&connector->display_info,
  250. &bus_format, 1);
  251.  
  252. return 1;
  253. }
  254.  
  255. static const struct drm_panel_funcs rb070d30_panel_funcs = {
  256. .get_modes = rb070d30_panel_get_modes,
  257. .prepare = rb070d30_panel_prepare,
  258. .enable = rb070d30_panel_enable,
  259. .disable = rb070d30_panel_disable,
  260. .unprepare = rb070d30_panel_unprepare,
  261. };
  262.  
  263. static int rb070d30_panel_dsi_probe(struct mipi_dsi_device *dsi)
  264. {
  265. struct rb070d30_panel *ctx;
  266. int ret;
  267.  
  268. ctx = devm_kzalloc(&dsi->dev, sizeof(*ctx), GFP_KERNEL);
  269. if (!ctx)
  270. return -ENOMEM;
  271.  
  272. /*
  273. ctx->supply = devm_regulator_get(&dsi->dev, "vcc-lcd");
  274. if (IS_ERR(ctx->supply))
  275. return PTR_ERR(ctx->supply);
  276. */
  277.  
  278. mipi_dsi_set_drvdata(dsi, ctx);
  279. ctx->dsi = dsi;
  280.  
  281. drm_panel_init(&ctx->panel, &dsi->dev, &rb070d30_panel_funcs,
  282. DRM_MODE_CONNECTOR_DSI);
  283.  
  284. ctx->gpios.reset = devm_gpiod_get(&dsi->dev, "reset", GPIOD_OUT_LOW);
  285. if (IS_ERR(ctx->gpios.reset)) {
  286. DRM_DEV_ERROR(&dsi->dev, "Couldn't get our reset GPIO\n");
  287. return PTR_ERR(ctx->gpios.reset);
  288. }
  289.  
  290. /*
  291. ctx->gpios.power = devm_gpiod_get(&dsi->dev, "power", GPIOD_OUT_LOW);
  292. if (IS_ERR(ctx->gpios.power)) {
  293. DRM_DEV_ERROR(&dsi->dev, "Couldn't get our power GPIO\n");
  294. return PTR_ERR(ctx->gpios.power);
  295. }
  296. */
  297.  
  298. /*
  299. * We don't change the state of that GPIO later on but we need
  300. * to force it into a low state.
  301. */
  302. /*
  303. ctx->gpios.updn = devm_gpiod_get(&dsi->dev, "updn", GPIOD_OUT_LOW);
  304. if (IS_ERR(ctx->gpios.updn)) {
  305. DRM_DEV_ERROR(&dsi->dev, "Couldn't get our updn GPIO\n");
  306. return PTR_ERR(ctx->gpios.updn);
  307. }*/
  308.  
  309. /*
  310. * We don't change the state of that GPIO later on but we need
  311. * to force it into a low state.
  312. */
  313. /*
  314. ctx->gpios.shlr = devm_gpiod_get(&dsi->dev, "shlr", GPIOD_OUT_LOW);
  315. if (IS_ERR(ctx->gpios.shlr)) {
  316. DRM_DEV_ERROR(&dsi->dev, "Couldn't get our shlr GPIO\n");
  317. return PTR_ERR(ctx->gpios.shlr);
  318. }
  319.  
  320. ctx->backlight = devm_of_find_backlight(&dsi->dev);
  321. if (IS_ERR(ctx->backlight)) {
  322. DRM_DEV_ERROR(&dsi->dev, "Couldn't get our backlight\n");
  323. return PTR_ERR(ctx->backlight);
  324. }*/
  325.  
  326. ret = drm_panel_add(&ctx->panel);
  327. if (ret < 0)
  328. return ret;
  329.  
  330. dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | MIPI_DSI_MODE_LPM;
  331. dsi->format = MIPI_DSI_FMT_RGB888;
  332. dsi->lanes = 2;
  333.  
  334. return mipi_dsi_attach(dsi);
  335. }
  336.  
  337. static int rb070d30_panel_dsi_remove(struct mipi_dsi_device *dsi)
  338. {
  339. struct rb070d30_panel *ctx = mipi_dsi_get_drvdata(dsi);
  340.  
  341. mipi_dsi_detach(dsi);
  342. drm_panel_remove(&ctx->panel);
  343.  
  344. return 0;
  345. }
  346.  
  347. static const struct of_device_id rb070d30_panel_of_match[] = {
  348. { .compatible = "dmb,rb070d30" },
  349. { /* sentinel */ },
  350. };
  351. MODULE_DEVICE_TABLE(of, rb070d30_panel_of_match);
  352.  
  353. static struct mipi_dsi_driver rb070d30_panel_driver = {
  354. .probe = rb070d30_panel_dsi_probe,
  355. .remove = rb070d30_panel_dsi_remove,
  356. .driver = {
  357. .name = "panel-dmb-rb070d30",
  358. .of_match_table = rb070d30_panel_of_match,
  359. },
  360. };
  361. module_mipi_dsi_driver(rb070d30_panel_driver);
  362.  
  363.  
  364. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement