dw-dphy-plat.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates.
  4. *
  5. * Synopsys DesignWare MIPI D-PHY controller driver.
  6. * Platform driver
  7. *
  8. * Author: Luis Oliveira <luis.oliveira@synopsys.com>
  9. */
  10. #include <dw-dphy-data.h>
  11. #include <dw-csi-data.h>
  12. #include "dw-dphy-rx.h"
  13. #include "bm_csi_hw.h"
  14. /* Global variable for compatibility mode, this could be override later */
  15. static int phy_type = 1; //Changed to fit single phy 0 - single | 1 - 8 lanes phy
  16. module_param(phy_type, int, 0664);
  17. MODULE_PARM_DESC(phy_type, "Disable compatibility mode for D-PHY G128");
  18. static struct phy_ops dw_dphy_ops = {
  19. .init = dw_dphy_init,
  20. .reset = dw_dphy_reset,
  21. .power_on = dw_dphy_power_on,
  22. .power_off = dw_dphy_power_off,
  23. .owner = THIS_MODULE,
  24. };
  25. static int get_resources(struct device *dev, struct dw_dphy_rx *dphy)
  26. {
  27. int ret = 0;
  28. struct platform_device *pdev = to_platform_device(dev);
  29. struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev);
  30. struct dw_phy_pdata *pdata = &drvdata->dphy_pdata;
  31. dphy->dphy_freq = pdata->dphy_frequency;
  32. dphy->dphy_te_len = pdata->dphy_te_len;
  33. dphy->dphy_gen = pdata->dphy_gen;
  34. drvdata->dphy = dphy;
  35. return ret;
  36. }
  37. static int phy_register(struct device *dev)
  38. {
  39. int ret = 0;
  40. struct platform_device *pdev = to_platform_device(dev);
  41. struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev);
  42. struct dw_dphy_rx *dphy = drvdata->dphy;
  43. struct dw_phy_pdata *pdata = &drvdata->dphy_pdata;
  44. ret = phy_create_lookup(dphy->phy,
  45. phys[pdata->id].name,
  46. csis[pdata->id].name);
  47. if (ret)
  48. dev_err(dev, "Failed to create dphy lookup\n");
  49. else
  50. dev_warn(dev, "Created dphy lookup [%s] --> [%s]\n",
  51. phys[pdata->id].name, csis[pdata->id].name);
  52. return ret;
  53. }
  54. static void phy_unregister(struct device *dev)
  55. {
  56. if (!dev->of_node) {
  57. struct platform_device *pdev = to_platform_device(dev);
  58. struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev);
  59. struct dw_dphy_rx *dphy = drvdata->dphy;
  60. struct dw_phy_pdata *pdata = &drvdata->dphy_pdata;
  61. phy_remove_lookup(dphy->phy,
  62. phys[pdata->id].name, csis[pdata->id].name);
  63. dev_warn(dev, "Removed dphy lookup [%s] --> [%s]\n",
  64. phys[pdata->id].name, csis[pdata->id].name);
  65. }
  66. }
  67. #define REG_DPHY_OFFSET 0x40
  68. int dw_dphy_rx_probe(struct platform_device *pdev, void __iomem *dphy1_if_addr)
  69. {
  70. struct device *dev = &pdev->dev;
  71. struct dw_dphy_rx *dphy;
  72. struct bm_csi_drvdata *drvdata;
  73. dphy = devm_kzalloc(&pdev->dev, sizeof(*dphy), GFP_KERNEL);
  74. if (!dphy)
  75. return -ENOMEM;
  76. drvdata = platform_get_drvdata(pdev);
  77. dphy->base_address = drvdata->base + REG_DPHY_OFFSET;
  78. drvdata->dphy= dphy;
  79. dphy->dphy1_if_addr = dphy1_if_addr;
  80. if (IS_ERR(dphy->base_address)) {
  81. dev_err(&pdev->dev, "error requesting base address\n");
  82. return PTR_ERR(dphy->base_address);
  83. }
  84. if (get_resources(dev, dphy)) {
  85. dev_err(dev, "failed to parse PHY resources\n");
  86. return -EINVAL;
  87. }
  88. dphy->phy = devm_phy_create(dev, NULL, &dw_dphy_ops);
  89. if (IS_ERR(dphy->phy)) {
  90. dev_err(dev, "failed to create PHY\n");
  91. return PTR_ERR(dphy->phy);
  92. }
  93. phy_set_drvdata(dphy->phy, dphy);
  94. if (phy_register(dev)) {
  95. dev_err(dev, "failed to register PHY\n");
  96. return -EINVAL;
  97. }
  98. dphy->lp_time = 1000; /* 1000 ns */
  99. dphy->lanes_config = dw_dphy_setup_config(dphy);
  100. dev_info(&dphy->phy->dev, "Probing dphy finished\n");
  101. #if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3)
  102. dw_dphy_create_capabilities_sysfs(pdev);
  103. #endif
  104. return 0;
  105. }
  106. int dw_dphy_rx_remove(struct platform_device *pdev)
  107. {
  108. struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev);
  109. struct dw_dphy_rx *dphy = drvdata->dphy;
  110. dev_info(&dphy->phy->dev, "phy removed\n");
  111. phy_unregister(&pdev->dev);
  112. dw_dphy_remove_capabilities_sysfs(pdev);
  113. return 0;
  114. }
  115. MODULE_DESCRIPTION("Synopsys DesignWare MIPI DPHY Rx driver");
  116. MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>");
  117. MODULE_LICENSE("GPL v2");