adv7533.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /*
  2. * Copyright (c) 2016, The Linux Foundation. All rights reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License version 2 and
  6. * only version 2 as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. */
  13. #include <linux/of_graph.h>
  14. #include "adv7511.h"
  15. static const struct reg_sequence adv7533_fixed_registers[] = {
  16. { 0x16, 0x20 },
  17. { 0x9a, 0xe0 },
  18. { 0xba, 0x70 },
  19. { 0xde, 0x82 },
  20. { 0xe4, 0x40 },
  21. { 0xe5, 0x80 },
  22. };
  23. static const struct reg_sequence adv7533_cec_fixed_registers[] = {
  24. { 0x15, 0xd0 },
  25. { 0x17, 0xd0 },
  26. { 0x24, 0x20 },
  27. { 0x57, 0x11 },
  28. };
  29. static const struct regmap_config adv7533_cec_regmap_config = {
  30. .reg_bits = 8,
  31. .val_bits = 8,
  32. .max_register = 0xff,
  33. .cache_type = REGCACHE_RBTREE,
  34. };
  35. static void adv7511_dsi_config_timing_gen(struct adv7511 *adv)
  36. {
  37. struct mipi_dsi_device *dsi = adv->dsi;
  38. struct drm_display_mode *mode = &adv->curr_mode;
  39. unsigned int hsw, hfp, hbp, vsw, vfp, vbp;
  40. u8 clock_div_by_lanes[] = { 6, 4, 3 }; /* 2, 3, 4 lanes */
  41. hsw = mode->hsync_end - mode->hsync_start;
  42. hfp = mode->hsync_start - mode->hdisplay;
  43. hbp = mode->htotal - mode->hsync_end;
  44. vsw = mode->vsync_end - mode->vsync_start;
  45. vfp = mode->vsync_start - mode->vdisplay;
  46. vbp = mode->vtotal - mode->vsync_end;
  47. /* set pixel clock divider mode */
  48. regmap_write(adv->regmap_cec, 0x16,
  49. clock_div_by_lanes[dsi->lanes - 2] << 3);
  50. /* horizontal porch params */
  51. regmap_write(adv->regmap_cec, 0x28, mode->htotal >> 4);
  52. regmap_write(adv->regmap_cec, 0x29, (mode->htotal << 4) & 0xff);
  53. regmap_write(adv->regmap_cec, 0x2a, hsw >> 4);
  54. regmap_write(adv->regmap_cec, 0x2b, (hsw << 4) & 0xff);
  55. regmap_write(adv->regmap_cec, 0x2c, hfp >> 4);
  56. regmap_write(adv->regmap_cec, 0x2d, (hfp << 4) & 0xff);
  57. regmap_write(adv->regmap_cec, 0x2e, hbp >> 4);
  58. regmap_write(adv->regmap_cec, 0x2f, (hbp << 4) & 0xff);
  59. /* vertical porch params */
  60. regmap_write(adv->regmap_cec, 0x30, mode->vtotal >> 4);
  61. regmap_write(adv->regmap_cec, 0x31, (mode->vtotal << 4) & 0xff);
  62. regmap_write(adv->regmap_cec, 0x32, vsw >> 4);
  63. regmap_write(adv->regmap_cec, 0x33, (vsw << 4) & 0xff);
  64. regmap_write(adv->regmap_cec, 0x34, vfp >> 4);
  65. regmap_write(adv->regmap_cec, 0x35, (vfp << 4) & 0xff);
  66. regmap_write(adv->regmap_cec, 0x36, vbp >> 4);
  67. regmap_write(adv->regmap_cec, 0x37, (vbp << 4) & 0xff);
  68. }
  69. void adv7533_dsi_power_on(struct adv7511 *adv)
  70. {
  71. struct mipi_dsi_device *dsi = adv->dsi;
  72. if (adv->use_timing_gen)
  73. adv7511_dsi_config_timing_gen(adv);
  74. /* set number of dsi lanes */
  75. regmap_write(adv->regmap_cec, 0x1c, dsi->lanes << 4);
  76. if (adv->use_timing_gen) {
  77. /* reset internal timing generator */
  78. regmap_write(adv->regmap_cec, 0x27, 0xcb);
  79. regmap_write(adv->regmap_cec, 0x27, 0x8b);
  80. regmap_write(adv->regmap_cec, 0x27, 0xcb);
  81. } else {
  82. /* disable internal timing generator */
  83. regmap_write(adv->regmap_cec, 0x27, 0x0b);
  84. }
  85. /* enable hdmi */
  86. regmap_write(adv->regmap_cec, 0x03, 0x89);
  87. /* disable test mode */
  88. regmap_write(adv->regmap_cec, 0x55, 0x00);
  89. regmap_register_patch(adv->regmap_cec, adv7533_cec_fixed_registers,
  90. ARRAY_SIZE(adv7533_cec_fixed_registers));
  91. }
  92. void adv7533_dsi_power_off(struct adv7511 *adv)
  93. {
  94. /* disable hdmi */
  95. regmap_write(adv->regmap_cec, 0x03, 0x0b);
  96. /* disable internal timing generator */
  97. regmap_write(adv->regmap_cec, 0x27, 0x0b);
  98. }
  99. void adv7533_mode_set(struct adv7511 *adv, struct drm_display_mode *mode)
  100. {
  101. struct mipi_dsi_device *dsi = adv->dsi;
  102. int lanes, ret;
  103. if (adv->num_dsi_lanes != 4)
  104. return;
  105. if (mode->clock > 80000)
  106. lanes = 4;
  107. else
  108. lanes = 3;
  109. if (lanes != dsi->lanes) {
  110. mipi_dsi_detach(dsi);
  111. dsi->lanes = lanes;
  112. ret = mipi_dsi_attach(dsi);
  113. if (ret)
  114. dev_err(&dsi->dev, "failed to change host lanes\n");
  115. }
  116. }
  117. int adv7533_patch_registers(struct adv7511 *adv)
  118. {
  119. return regmap_register_patch(adv->regmap,
  120. adv7533_fixed_registers,
  121. ARRAY_SIZE(adv7533_fixed_registers));
  122. }
  123. void adv7533_uninit_cec(struct adv7511 *adv)
  124. {
  125. i2c_unregister_device(adv->i2c_cec);
  126. }
  127. int adv7533_init_cec(struct adv7511 *adv)
  128. {
  129. int ret;
  130. adv->i2c_cec = i2c_new_dummy(adv->i2c_main->adapter,
  131. adv->i2c_main->addr - 1);
  132. if (!adv->i2c_cec)
  133. return -ENOMEM;
  134. adv->regmap_cec = devm_regmap_init_i2c(adv->i2c_cec,
  135. &adv7533_cec_regmap_config);
  136. if (IS_ERR(adv->regmap_cec)) {
  137. ret = PTR_ERR(adv->regmap_cec);
  138. goto err;
  139. }
  140. ret = regmap_register_patch(adv->regmap_cec,
  141. adv7533_cec_fixed_registers,
  142. ARRAY_SIZE(adv7533_cec_fixed_registers));
  143. if (ret)
  144. goto err;
  145. return 0;
  146. err:
  147. adv7533_uninit_cec(adv);
  148. return ret;
  149. }
  150. int adv7533_attach_dsi(struct adv7511 *adv)
  151. {
  152. struct device *dev = &adv->i2c_main->dev;
  153. struct mipi_dsi_host *host;
  154. struct mipi_dsi_device *dsi;
  155. int ret = 0;
  156. const struct mipi_dsi_device_info info = { .type = "adv7533",
  157. .channel = 0,
  158. .node = NULL,
  159. };
  160. host = of_find_mipi_dsi_host_by_node(adv->host_node);
  161. if (!host) {
  162. dev_err(dev, "failed to find dsi host\n");
  163. return -EPROBE_DEFER;
  164. }
  165. dsi = mipi_dsi_device_register_full(host, &info);
  166. if (IS_ERR(dsi)) {
  167. dev_err(dev, "failed to create dsi device\n");
  168. ret = PTR_ERR(dsi);
  169. goto err_dsi_device;
  170. }
  171. adv->dsi = dsi;
  172. dsi->lanes = adv->num_dsi_lanes;
  173. dsi->format = MIPI_DSI_FMT_RGB888;
  174. dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE |
  175. MIPI_DSI_MODE_EOT_PACKET | MIPI_DSI_MODE_VIDEO_HSE;
  176. ret = mipi_dsi_attach(dsi);
  177. if (ret < 0) {
  178. dev_err(dev, "failed to attach dsi to host\n");
  179. goto err_dsi_attach;
  180. }
  181. return 0;
  182. err_dsi_attach:
  183. mipi_dsi_device_unregister(dsi);
  184. err_dsi_device:
  185. return ret;
  186. }
  187. void adv7533_detach_dsi(struct adv7511 *adv)
  188. {
  189. mipi_dsi_detach(adv->dsi);
  190. mipi_dsi_device_unregister(adv->dsi);
  191. }
  192. int adv7533_parse_dt(struct device_node *np, struct adv7511 *adv)
  193. {
  194. u32 num_lanes;
  195. struct device_node *endpoint;
  196. of_property_read_u32(np, "adi,dsi-lanes", &num_lanes);
  197. if (num_lanes < 1 || num_lanes > 4)
  198. return -EINVAL;
  199. adv->num_dsi_lanes = num_lanes;
  200. endpoint = of_graph_get_next_endpoint(np, NULL);
  201. if (!endpoint)
  202. return -ENODEV;
  203. adv->host_node = of_graph_get_remote_port_parent(endpoint);
  204. if (!adv->host_node) {
  205. of_node_put(endpoint);
  206. return -ENODEV;
  207. }
  208. of_node_put(endpoint);
  209. of_node_put(adv->host_node);
  210. adv->use_timing_gen = !of_property_read_bool(np,
  211. "adi,disable-timing-generator");
  212. /* TODO: Check if these need to be parsed by DT or not */
  213. adv->rgb = true;
  214. adv->embedded_sync = false;
  215. return 0;
  216. }