It does so by adding the following changes:
1. Introducing SCSI_UFS_QCOM as a platform device. Its probe
   function registers a set of vops to its driver_data.
2. Adding an optional device tree sub-node, under SCSI_UFSHCD_PLATFORM.
   Now, the probe function of SCSI_UFSHCD_PLATFORM invokes the probe
   function of its sub-node (if it exists), by calling
   of_platform_populate(). It ensures that vops are set, and ready to
   be used, by the time the UFSHCD driver starts its initialization
   procedure.

Signed-off-by: Yaniv Gardi <yga...@codeaurora.org>

---
 .../devicetree/bindings/ufs/ufshcd-pltfrm.txt      |  8 +++++
 drivers/scsi/ufs/ufs-qcom.c                        | 40 ++++++++++++++++++++++
 drivers/scsi/ufs/ufshcd-pltfrm.c                   | 33 +++++++++++-------
 3 files changed, 68 insertions(+), 13 deletions(-)

diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt 
b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 5357919..e2f3058 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -55,3 +55,11 @@ Example:
                clock-names = "core_clk", "ref_clk", "iface_clk";
                freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
        };
+
+This is an example to a variant sub-node of ufshc:
+       ufs_variant {
+               compatible = "qcom,ufs_variant";
+       };
+
+This sub-node holds various specific information that is not defined in the
+standard and that may differ between platforms.
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 6671a8e..ad5ffa8 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -1018,4 +1018,44 @@ static const struct ufs_hba_variant_ops 
ufs_hba_qcom_vops = {
 };
 EXPORT_SYMBOL(ufs_hba_qcom_vops);
 
+/**
+ * ufs_qcom_probe - probe routine of the driver
+ * @pdev: pointer to Platform device handle
+ *
+ * Always return 0
+ */
+static int ufs_qcom_probe(struct platform_device *pdev)
+{
+       dev_set_drvdata(&pdev->dev, (void *)&ufs_hba_qcom_vops);
+       return 0;
+}
+
+/**
+ * ufs_qcom_remove - set driver_data of the device to NULL
+ * @pdev: pointer to platform device handle
+ *
+ * Always return 0
+ */
+static int ufs_qcom_remove(struct platform_device *pdev)
+{
+       dev_set_drvdata(&pdev->dev, NULL);
+       return 0;
+}
+
+static const struct of_device_id ufs_qcom_of_match[] = {
+       { .compatible = "qcom,ufs_variant"},
+       {},
+};
+
+static struct platform_driver ufs_qcom_pltform = {
+       .probe  = ufs_qcom_probe,
+       .remove = ufs_qcom_remove,
+       .driver = {
+               .name   = "ufs_qcom",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(ufs_qcom_of_match),
+       },
+};
+module_platform_driver(ufs_qcom_pltform);
+
 MODULE_LICENSE("GPL v2");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7db9564..7bf2f44 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -36,22 +36,11 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include "ufshcd.h"
 
 static const struct of_device_id ufs_of_match[];
-static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
-{
-       if (dev->of_node) {
-               const struct of_device_id *match;
-
-               match = of_match_node(ufs_of_match, dev->of_node);
-               if (match)
-                       return (struct ufs_hba_variant_ops *)match->data;
-       }
-
-       return NULL;
-}
 
 static int ufshcd_parse_clock_info(struct ufs_hba *hba)
 {
@@ -300,6 +289,9 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
        struct resource *mem_res;
        int irq, err;
        struct device *dev = &pdev->dev;
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *ufs_variant_node;
+       struct platform_device *ufs_variant_pdev;
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        mmio_base = devm_ioremap_resource(dev, mem_res);
@@ -321,7 +313,22 @@ static int ufshcd_pltfrm_probe(struct platform_device 
*pdev)
                goto out;
        }
 
-       hba->vops = get_variant_ops(&pdev->dev);
+       err = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       if (err)
+               dev_err(&pdev->dev,
+                       "%s: of_platform_populate() failed\n", __func__);
+
+       ufs_variant_node = of_get_next_available_child(node, NULL);
+
+       if (!ufs_variant_node) {
+               dev_dbg(&pdev->dev, "failed to find ufs_variant_node child\n");
+       } else {
+               ufs_variant_pdev = of_find_device_by_node(ufs_variant_node);
+
+               if (ufs_variant_pdev)
+                       hba->vops = (struct ufs_hba_variant_ops *)
+                               dev_get_drvdata(&ufs_variant_pdev->dev);
+       }
 
        err = ufshcd_parse_clock_info(hba);
        if (err) {
-- 
1.8.5.2

-- 
QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member of 
Code Aurora Forum, hosted by The Linux Foundation
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to