rcar_dw_hdmi.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * R-Car Gen3 HDMI PHY
  4. *
  5. * Copyright (C) 2016 Renesas Electronics Corporation
  6. *
  7. * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
  8. */
  9. #include <linux/module.h>
  10. #include <linux/platform_device.h>
  11. #include <drm/bridge/dw_hdmi.h>
  12. #define RCAR_HDMI_PHY_OPMODE_PLLCFG 0x06 /* Mode of operation and PLL dividers */
  13. #define RCAR_HDMI_PHY_PLLCURRGMPCTRL 0x10 /* PLL current and Gmp (conductance) */
  14. #define RCAR_HDMI_PHY_PLLDIVCTRL 0x11 /* PLL dividers */
  15. struct rcar_hdmi_phy_params {
  16. unsigned long mpixelclock;
  17. u16 opmode_div; /* Mode of operation and PLL dividers */
  18. u16 curr_gmp; /* PLL current and Gmp (conductance) */
  19. u16 div; /* PLL dividers */
  20. };
  21. static const struct rcar_hdmi_phy_params rcar_hdmi_phy_params[] = {
  22. { 35500000, 0x0003, 0x0344, 0x0328 },
  23. { 44900000, 0x0003, 0x0285, 0x0128 },
  24. { 71000000, 0x0002, 0x1184, 0x0314 },
  25. { 90000000, 0x0002, 0x1144, 0x0114 },
  26. { 140250000, 0x0001, 0x20c4, 0x030a },
  27. { 182750000, 0x0001, 0x2084, 0x010a },
  28. { 281250000, 0x0000, 0x0084, 0x0305 },
  29. { 297000000, 0x0000, 0x0084, 0x0105 },
  30. { ~0UL, 0x0000, 0x0000, 0x0000 },
  31. };
  32. static int rcar_hdmi_phy_configure(struct dw_hdmi *hdmi,
  33. const struct dw_hdmi_plat_data *pdata,
  34. unsigned long mpixelclock)
  35. {
  36. const struct rcar_hdmi_phy_params *params = rcar_hdmi_phy_params;
  37. for (; params->mpixelclock != ~0UL; ++params) {
  38. if (mpixelclock <= params->mpixelclock)
  39. break;
  40. }
  41. if (params->mpixelclock == ~0UL)
  42. return -EINVAL;
  43. dw_hdmi_phy_i2c_write(hdmi, params->opmode_div,
  44. RCAR_HDMI_PHY_OPMODE_PLLCFG);
  45. dw_hdmi_phy_i2c_write(hdmi, params->curr_gmp,
  46. RCAR_HDMI_PHY_PLLCURRGMPCTRL);
  47. dw_hdmi_phy_i2c_write(hdmi, params->div, RCAR_HDMI_PHY_PLLDIVCTRL);
  48. return 0;
  49. }
  50. static const struct dw_hdmi_plat_data rcar_dw_hdmi_plat_data = {
  51. .configure_phy = rcar_hdmi_phy_configure,
  52. };
  53. static int rcar_dw_hdmi_probe(struct platform_device *pdev)
  54. {
  55. struct dw_hdmi *hdmi;
  56. hdmi = dw_hdmi_probe(pdev, &rcar_dw_hdmi_plat_data);
  57. if (IS_ERR(hdmi))
  58. return PTR_ERR(hdmi);
  59. platform_set_drvdata(pdev, hdmi);
  60. return 0;
  61. }
  62. static int rcar_dw_hdmi_remove(struct platform_device *pdev)
  63. {
  64. struct dw_hdmi *hdmi = platform_get_drvdata(pdev);
  65. dw_hdmi_remove(hdmi);
  66. return 0;
  67. }
  68. static const struct of_device_id rcar_dw_hdmi_of_table[] = {
  69. { .compatible = "renesas,rcar-gen3-hdmi" },
  70. { /* Sentinel */ },
  71. };
  72. MODULE_DEVICE_TABLE(of, rcar_dw_hdmi_of_table);
  73. static struct platform_driver rcar_dw_hdmi_platform_driver = {
  74. .probe = rcar_dw_hdmi_probe,
  75. .remove = rcar_dw_hdmi_remove,
  76. .driver = {
  77. .name = "rcar-dw-hdmi",
  78. .of_match_table = rcar_dw_hdmi_of_table,
  79. },
  80. };
  81. module_platform_driver(rcar_dw_hdmi_platform_driver);
  82. MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
  83. MODULE_DESCRIPTION("Renesas R-Car Gen3 HDMI Encoder Driver");
  84. MODULE_LICENSE("GPL");