All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
To: Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Vinod Koul <vkoul@kernel.org>,
	Kishon Vijay Abraham I <kishon@ti.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>,
	linux-arm-msm@vger.kernel.org, linux-phy@lists.infradead.org
Subject: [RFC PATCH v2 12/34] phy: qcom-qmp: add QMP UFS PHY driver
Date: Thu, 26 May 2022 02:58:19 +0300	[thread overview]
Message-ID: <20220525235841.852301-13-dmitry.baryshkov@linaro.org> (raw)
In-Reply-To: <20220525235841.852301-1-dmitry.baryshkov@linaro.org>

Add a split out QMP UFS PHY driver. No hardware support is supported,
it's just a template for now.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/phy/qualcomm/Makefile           |   1 +
 drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 313 ++++++++++++++++++++++++
 2 files changed, 314 insertions(+)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-ufs.c

diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index 5e805b7a530b..85152016aa5a 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_QCOM_PCIE2)		+= phy-qcom-pcie2.o
 obj-$(CONFIG_PHY_QCOM_QMP)		+= \
 	phy-qcom-qmp-lib.o \
 	phy-qcom-qmp-pcie.o \
+	phy-qcom-qmp-ufs.o \
 	phy-qcom-qmp.o
 
 obj-$(CONFIG_PHY_QCOM_QUSB2)		+= phy-qcom-qusb2.o
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
new file mode 100644
index 000000000000..5136b161a372
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/phy/phy.h>
+
+#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-lib.h"
+
+struct qmp_ufs_phy;
+
+/* struct qmp_phy_ufs_cfg - per-PHY initialization config */
+struct qmp_phy_ufs_cfg {
+	struct qmp_phy_cfg base;
+
+	/* true, if PCS block has no separate SW_RESET register */
+	bool no_pcs_sw_reset;
+};
+
+/**
+ * struct qmp_ufs_phy - per-lane phy descriptor
+ *
+ * @base: base qmp_phy data
+ * @cfg: phy specific configuration
+ * @ufs_reset: optional UFS PHY reset handle
+ */
+struct qmp_ufs_phy {
+	struct qmp_phy base;
+	const struct qmp_phy_ufs_cfg *cfg;
+	struct reset_control *ufs_reset;
+};
+
+#define to_qmp_ufs_phy(qphy)	container_of(qphy, struct qmp_ufs_phy, base)
+
+static int qcom_qmp_phy_com_init(struct qmp_ufs_phy *qphy_ufs)
+{
+	struct qcom_qmp *qmp = qphy_ufs->base.qmp;
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+	int ret;
+
+	dev_vdbg(qmp->dev, "Initializing QMP phy\n");
+
+	mutex_lock(&qmp->phy_mutex);
+	if (qmp->init_count++) {
+		mutex_unlock(&qmp->phy_mutex);
+		return 0;
+	}
+
+	ret = qcom_qmp_phy_common_init(&qphy_ufs->base, &cfg->base);
+	if (ret)
+		goto err_unlock;
+
+	qcom_qmp_phy_pwrup(&qphy_ufs->base, &cfg->base);
+
+	mutex_unlock(&qmp->phy_mutex);
+
+	return 0;
+
+err_unlock:
+	mutex_unlock(&qmp->phy_mutex);
+
+	return ret;
+}
+
+static int qcom_qmp_phy_com_exit(struct qmp_ufs_phy *qphy_ufs)
+{
+	struct qcom_qmp *qmp = qphy_ufs->base.qmp;
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+
+	mutex_lock(&qmp->phy_mutex);
+	if (--qmp->init_count) {
+		mutex_unlock(&qmp->phy_mutex);
+		return 0;
+	}
+
+	reset_control_assert(qphy_ufs->ufs_reset);
+
+	qcom_qmp_phy_common_exit(&qphy_ufs->base, &cfg->base);
+
+	mutex_unlock(&qmp->phy_mutex);
+
+	return 0;
+}
+
+static int qcom_qmp_phy_ufs_init(struct qmp_ufs_phy *qphy_ufs)
+{
+	struct qcom_qmp *qmp = qphy_ufs->base.qmp;
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+	int ret;
+
+	if (!cfg->no_pcs_sw_reset)
+		return 0;
+
+	/*
+	 * Get UFS reset, which is delayed until now to avoid a
+	 * circular dependency where UFS needs its PHY, but the PHY
+	 * needs this UFS reset.
+	 */
+	if (!qphy_ufs->ufs_reset) {
+		qphy_ufs->ufs_reset =
+			devm_reset_control_get_exclusive(qmp->dev,
+							 "ufsphy");
+
+		if (IS_ERR(qphy_ufs->ufs_reset)) {
+			ret = PTR_ERR(qphy_ufs->ufs_reset);
+			dev_err(qmp->dev,
+				"failed to get UFS reset: %d\n",
+				ret);
+
+			qphy_ufs->ufs_reset = NULL;
+			return ret;
+		}
+	}
+
+	ret = reset_control_assert(qphy_ufs->ufs_reset);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int qcom_qmp_phy_ufs_power_on(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+	void __iomem *serdes = qphy_ufs->base.serdes;
+	void __iomem *tx = qphy_ufs->base.tx;
+	void __iomem *rx = qphy_ufs->base.rx;
+	void __iomem *pcs = qphy_ufs->base.pcs;
+	int ret;
+
+	qcom_qmp_phy_configure(serdes, cfg->base.regs,
+			cfg->base.serdes_tbl, cfg->base.serdes_tbl_num);
+
+	/* Tx, Rx, and PCS configurations */
+	qcom_qmp_phy_configure_lane(tx, cfg->base.regs,
+				    cfg->base.tx_tbl, cfg->base.tx_tbl_num, 1);
+
+	/* Configuration for other LANE for USB-DP combo PHY */
+	if (cfg->base.is_dual_lane_phy)
+		qcom_qmp_phy_configure_lane(qphy_ufs->base.tx2, cfg->base.regs,
+					    cfg->base.tx_tbl, cfg->base.tx_tbl_num, 2);
+
+	qcom_qmp_phy_configure_lane(rx, cfg->base.regs,
+				    cfg->base.rx_tbl, cfg->base.rx_tbl_num, 1);
+
+	if (cfg->base.is_dual_lane_phy)
+		qcom_qmp_phy_configure_lane(qphy_ufs->base.rx2, cfg->base.regs,
+					    cfg->base.rx_tbl, cfg->base.rx_tbl_num, 2);
+
+	qcom_qmp_phy_configure(pcs, cfg->base.regs, cfg->base.pcs_tbl, cfg->base.pcs_tbl_num);
+
+	ret = reset_control_deassert(qphy_ufs->ufs_reset);
+	if (ret)
+		return ret;
+
+	return qcom_qmp_phy_power_on(qphy, &cfg->base, !cfg->no_pcs_sw_reset);
+}
+
+static int qcom_qmp_phy_ufs_power_off(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+
+	qcom_qmp_phy_power_off(qphy, &cfg->base, !cfg->no_pcs_sw_reset);
+
+	return 0;
+}
+
+static int qcom_qmp_phy_ufs_enable(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	int ret;
+
+	ret = qcom_qmp_phy_ufs_init(qphy_ufs);
+	if (ret)
+		return ret;
+
+	ret = qcom_qmp_phy_com_init(qphy_ufs);
+	if (ret)
+		return ret;
+
+	ret = qcom_qmp_phy_ufs_power_on(phy);
+	if (ret)
+		qcom_qmp_phy_com_exit(qphy_ufs);
+
+	return ret;
+}
+
+static int qcom_qmp_phy_ufs_disable(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	int ret;
+
+	ret = qcom_qmp_phy_ufs_power_off(phy);
+	if (ret)
+		return ret;
+	return qcom_qmp_phy_com_exit(qphy_ufs);
+}
+
+static const struct phy_ops qcom_qmp_ufs_ops = {
+	.power_on	= qcom_qmp_phy_ufs_enable,
+	.power_off	= qcom_qmp_phy_ufs_disable,
+	.set_mode	= qcom_qmp_phy_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static
+int qcom_qmp_phy_ufs_create(struct device *dev, struct device_node *np, int id,
+			void __iomem *serdes, const struct qmp_phy_ufs_cfg *cfg)
+{
+	struct qmp_ufs_phy *qphy_ufs;
+	int ret;
+
+	qphy_ufs = devm_kzalloc(dev, sizeof(*qphy_ufs), GFP_KERNEL);
+	if (!qphy_ufs)
+		return -ENOMEM;
+
+	qphy_ufs->cfg = cfg;
+
+	ret = qcom_qmp_phy_init(dev, np, &qphy_ufs->base, serdes, &cfg->base);
+	if (ret)
+		return ret;
+
+	ret = qcom_qmp_phy_setup(dev, np, id, &qphy_ufs->base, &qcom_qmp_ufs_ops);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id qcom_qmp_phy_ufs_of_match_table[] = {
+	{ },
+};
+MODULE_DEVICE_TABLE(of, qcom_qmp_phy_ufs_of_match_table);
+
+static int qcom_qmp_phy_ufs_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *child;
+	struct phy_provider *phy_provider;
+	void __iomem *serdes;
+	const struct qmp_phy_ufs_cfg *cfg;
+	int id;
+	int ret;
+
+	/* Get the specific init parameters of QMP phy */
+	cfg = of_device_get_match_data(dev);
+	if (!cfg)
+		return -EINVAL;
+
+	/* per PHY serdes; usually located at base address */
+	serdes = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(serdes))
+		return PTR_ERR(serdes);
+
+	ret = qcom_qmp_phy_common_probe(pdev, &cfg->base, cfg->base.nlanes);
+	if (ret)
+		return ret;
+
+	id = 0;
+	for_each_available_child_of_node(dev->of_node, child) {
+		/* Create per-lane phy */
+		ret = qcom_qmp_phy_ufs_create(dev, child, id, serdes, cfg);
+		if (ret) {
+			dev_err(dev, "failed to create lane%d phy, %d\n",
+				id, ret);
+			goto err_node_put;
+		}
+
+		id++;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	if (!IS_ERR(phy_provider))
+		dev_info(dev, "Registered Qcom-QMP phy\n");
+	else
+		pm_runtime_disable(dev);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+
+err_node_put:
+	pm_runtime_disable(dev);
+	of_node_put(child);
+	return ret;
+}
+
+static struct platform_driver qcom_qmp_phy_ufs_driver = {
+	.probe		= qcom_qmp_phy_ufs_probe,
+	.driver = {
+		.name	= "qcom-qmp-phy-ufs",
+		.of_match_table = qcom_qmp_phy_ufs_of_match_table,
+	},
+};
+
+module_platform_driver(qcom_qmp_phy_ufs_driver);
+
+MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm QMP UFS PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.35.1


WARNING: multiple messages have this Message-ID (diff)
From: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
To: Andy Gross <agross@kernel.org>,
	Bjorn Andersson <bjorn.andersson@linaro.org>,
	Vinod Koul <vkoul@kernel.org>,
	Kishon Vijay Abraham I <kishon@ti.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>,
	linux-arm-msm@vger.kernel.org, linux-phy@lists.infradead.org
Subject: [RFC PATCH v2 12/34] phy: qcom-qmp: add QMP UFS PHY driver
Date: Thu, 26 May 2022 02:58:19 +0300	[thread overview]
Message-ID: <20220525235841.852301-13-dmitry.baryshkov@linaro.org> (raw)
In-Reply-To: <20220525235841.852301-1-dmitry.baryshkov@linaro.org>

Add a split out QMP UFS PHY driver. No hardware support is supported,
it's just a template for now.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
---
 drivers/phy/qualcomm/Makefile           |   1 +
 drivers/phy/qualcomm/phy-qcom-qmp-ufs.c | 313 ++++++++++++++++++++++++
 2 files changed, 314 insertions(+)
 create mode 100644 drivers/phy/qualcomm/phy-qcom-qmp-ufs.c

diff --git a/drivers/phy/qualcomm/Makefile b/drivers/phy/qualcomm/Makefile
index 5e805b7a530b..85152016aa5a 100644
--- a/drivers/phy/qualcomm/Makefile
+++ b/drivers/phy/qualcomm/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PHY_QCOM_PCIE2)		+= phy-qcom-pcie2.o
 obj-$(CONFIG_PHY_QCOM_QMP)		+= \
 	phy-qcom-qmp-lib.o \
 	phy-qcom-qmp-pcie.o \
+	phy-qcom-qmp-ufs.o \
 	phy-qcom-qmp.o
 
 obj-$(CONFIG_PHY_QCOM_QUSB2)		+= phy-qcom-qusb2.o
diff --git a/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
new file mode 100644
index 000000000000..5136b161a372
--- /dev/null
+++ b/drivers/phy/qualcomm/phy-qcom-qmp-ufs.c
@@ -0,0 +1,313 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ */
+
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <dt-bindings/phy/phy.h>
+
+#include "phy-qcom-qmp.h"
+#include "phy-qcom-qmp-lib.h"
+
+struct qmp_ufs_phy;
+
+/* struct qmp_phy_ufs_cfg - per-PHY initialization config */
+struct qmp_phy_ufs_cfg {
+	struct qmp_phy_cfg base;
+
+	/* true, if PCS block has no separate SW_RESET register */
+	bool no_pcs_sw_reset;
+};
+
+/**
+ * struct qmp_ufs_phy - per-lane phy descriptor
+ *
+ * @base: base qmp_phy data
+ * @cfg: phy specific configuration
+ * @ufs_reset: optional UFS PHY reset handle
+ */
+struct qmp_ufs_phy {
+	struct qmp_phy base;
+	const struct qmp_phy_ufs_cfg *cfg;
+	struct reset_control *ufs_reset;
+};
+
+#define to_qmp_ufs_phy(qphy)	container_of(qphy, struct qmp_ufs_phy, base)
+
+static int qcom_qmp_phy_com_init(struct qmp_ufs_phy *qphy_ufs)
+{
+	struct qcom_qmp *qmp = qphy_ufs->base.qmp;
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+	int ret;
+
+	dev_vdbg(qmp->dev, "Initializing QMP phy\n");
+
+	mutex_lock(&qmp->phy_mutex);
+	if (qmp->init_count++) {
+		mutex_unlock(&qmp->phy_mutex);
+		return 0;
+	}
+
+	ret = qcom_qmp_phy_common_init(&qphy_ufs->base, &cfg->base);
+	if (ret)
+		goto err_unlock;
+
+	qcom_qmp_phy_pwrup(&qphy_ufs->base, &cfg->base);
+
+	mutex_unlock(&qmp->phy_mutex);
+
+	return 0;
+
+err_unlock:
+	mutex_unlock(&qmp->phy_mutex);
+
+	return ret;
+}
+
+static int qcom_qmp_phy_com_exit(struct qmp_ufs_phy *qphy_ufs)
+{
+	struct qcom_qmp *qmp = qphy_ufs->base.qmp;
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+
+	mutex_lock(&qmp->phy_mutex);
+	if (--qmp->init_count) {
+		mutex_unlock(&qmp->phy_mutex);
+		return 0;
+	}
+
+	reset_control_assert(qphy_ufs->ufs_reset);
+
+	qcom_qmp_phy_common_exit(&qphy_ufs->base, &cfg->base);
+
+	mutex_unlock(&qmp->phy_mutex);
+
+	return 0;
+}
+
+static int qcom_qmp_phy_ufs_init(struct qmp_ufs_phy *qphy_ufs)
+{
+	struct qcom_qmp *qmp = qphy_ufs->base.qmp;
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+	int ret;
+
+	if (!cfg->no_pcs_sw_reset)
+		return 0;
+
+	/*
+	 * Get UFS reset, which is delayed until now to avoid a
+	 * circular dependency where UFS needs its PHY, but the PHY
+	 * needs this UFS reset.
+	 */
+	if (!qphy_ufs->ufs_reset) {
+		qphy_ufs->ufs_reset =
+			devm_reset_control_get_exclusive(qmp->dev,
+							 "ufsphy");
+
+		if (IS_ERR(qphy_ufs->ufs_reset)) {
+			ret = PTR_ERR(qphy_ufs->ufs_reset);
+			dev_err(qmp->dev,
+				"failed to get UFS reset: %d\n",
+				ret);
+
+			qphy_ufs->ufs_reset = NULL;
+			return ret;
+		}
+	}
+
+	ret = reset_control_assert(qphy_ufs->ufs_reset);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int qcom_qmp_phy_ufs_power_on(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+	void __iomem *serdes = qphy_ufs->base.serdes;
+	void __iomem *tx = qphy_ufs->base.tx;
+	void __iomem *rx = qphy_ufs->base.rx;
+	void __iomem *pcs = qphy_ufs->base.pcs;
+	int ret;
+
+	qcom_qmp_phy_configure(serdes, cfg->base.regs,
+			cfg->base.serdes_tbl, cfg->base.serdes_tbl_num);
+
+	/* Tx, Rx, and PCS configurations */
+	qcom_qmp_phy_configure_lane(tx, cfg->base.regs,
+				    cfg->base.tx_tbl, cfg->base.tx_tbl_num, 1);
+
+	/* Configuration for other LANE for USB-DP combo PHY */
+	if (cfg->base.is_dual_lane_phy)
+		qcom_qmp_phy_configure_lane(qphy_ufs->base.tx2, cfg->base.regs,
+					    cfg->base.tx_tbl, cfg->base.tx_tbl_num, 2);
+
+	qcom_qmp_phy_configure_lane(rx, cfg->base.regs,
+				    cfg->base.rx_tbl, cfg->base.rx_tbl_num, 1);
+
+	if (cfg->base.is_dual_lane_phy)
+		qcom_qmp_phy_configure_lane(qphy_ufs->base.rx2, cfg->base.regs,
+					    cfg->base.rx_tbl, cfg->base.rx_tbl_num, 2);
+
+	qcom_qmp_phy_configure(pcs, cfg->base.regs, cfg->base.pcs_tbl, cfg->base.pcs_tbl_num);
+
+	ret = reset_control_deassert(qphy_ufs->ufs_reset);
+	if (ret)
+		return ret;
+
+	return qcom_qmp_phy_power_on(qphy, &cfg->base, !cfg->no_pcs_sw_reset);
+}
+
+static int qcom_qmp_phy_ufs_power_off(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	const struct qmp_phy_ufs_cfg *cfg = qphy_ufs->cfg;
+
+	qcom_qmp_phy_power_off(qphy, &cfg->base, !cfg->no_pcs_sw_reset);
+
+	return 0;
+}
+
+static int qcom_qmp_phy_ufs_enable(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	int ret;
+
+	ret = qcom_qmp_phy_ufs_init(qphy_ufs);
+	if (ret)
+		return ret;
+
+	ret = qcom_qmp_phy_com_init(qphy_ufs);
+	if (ret)
+		return ret;
+
+	ret = qcom_qmp_phy_ufs_power_on(phy);
+	if (ret)
+		qcom_qmp_phy_com_exit(qphy_ufs);
+
+	return ret;
+}
+
+static int qcom_qmp_phy_ufs_disable(struct phy *phy)
+{
+	struct qmp_phy *qphy = phy_get_drvdata(phy);
+	struct qmp_ufs_phy *qphy_ufs = to_qmp_ufs_phy(qphy);
+	int ret;
+
+	ret = qcom_qmp_phy_ufs_power_off(phy);
+	if (ret)
+		return ret;
+	return qcom_qmp_phy_com_exit(qphy_ufs);
+}
+
+static const struct phy_ops qcom_qmp_ufs_ops = {
+	.power_on	= qcom_qmp_phy_ufs_enable,
+	.power_off	= qcom_qmp_phy_ufs_disable,
+	.set_mode	= qcom_qmp_phy_set_mode,
+	.owner		= THIS_MODULE,
+};
+
+static
+int qcom_qmp_phy_ufs_create(struct device *dev, struct device_node *np, int id,
+			void __iomem *serdes, const struct qmp_phy_ufs_cfg *cfg)
+{
+	struct qmp_ufs_phy *qphy_ufs;
+	int ret;
+
+	qphy_ufs = devm_kzalloc(dev, sizeof(*qphy_ufs), GFP_KERNEL);
+	if (!qphy_ufs)
+		return -ENOMEM;
+
+	qphy_ufs->cfg = cfg;
+
+	ret = qcom_qmp_phy_init(dev, np, &qphy_ufs->base, serdes, &cfg->base);
+	if (ret)
+		return ret;
+
+	ret = qcom_qmp_phy_setup(dev, np, id, &qphy_ufs->base, &qcom_qmp_ufs_ops);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static const struct of_device_id qcom_qmp_phy_ufs_of_match_table[] = {
+	{ },
+};
+MODULE_DEVICE_TABLE(of, qcom_qmp_phy_ufs_of_match_table);
+
+static int qcom_qmp_phy_ufs_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *child;
+	struct phy_provider *phy_provider;
+	void __iomem *serdes;
+	const struct qmp_phy_ufs_cfg *cfg;
+	int id;
+	int ret;
+
+	/* Get the specific init parameters of QMP phy */
+	cfg = of_device_get_match_data(dev);
+	if (!cfg)
+		return -EINVAL;
+
+	/* per PHY serdes; usually located at base address */
+	serdes = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(serdes))
+		return PTR_ERR(serdes);
+
+	ret = qcom_qmp_phy_common_probe(pdev, &cfg->base, cfg->base.nlanes);
+	if (ret)
+		return ret;
+
+	id = 0;
+	for_each_available_child_of_node(dev->of_node, child) {
+		/* Create per-lane phy */
+		ret = qcom_qmp_phy_ufs_create(dev, child, id, serdes, cfg);
+		if (ret) {
+			dev_err(dev, "failed to create lane%d phy, %d\n",
+				id, ret);
+			goto err_node_put;
+		}
+
+		id++;
+	}
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	if (!IS_ERR(phy_provider))
+		dev_info(dev, "Registered Qcom-QMP phy\n");
+	else
+		pm_runtime_disable(dev);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+
+err_node_put:
+	pm_runtime_disable(dev);
+	of_node_put(child);
+	return ret;
+}
+
+static struct platform_driver qcom_qmp_phy_ufs_driver = {
+	.probe		= qcom_qmp_phy_ufs_probe,
+	.driver = {
+		.name	= "qcom-qmp-phy-ufs",
+		.of_match_table = qcom_qmp_phy_ufs_of_match_table,
+	},
+};
+
+module_platform_driver(qcom_qmp_phy_ufs_driver);
+
+MODULE_AUTHOR("Vivek Gautam <vivek.gautam@codeaurora.org>");
+MODULE_DESCRIPTION("Qualcomm QMP UFS PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.35.1


-- 
linux-phy mailing list
linux-phy@lists.infradead.org
https://lists.infradead.org/mailman/listinfo/linux-phy

  parent reply	other threads:[~2022-05-25 23:59 UTC|newest]

Thread overview: 70+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-25 23:58 [RFC PATCH v2 00/34] phy: qcom-qmp: split the QMP PHY driver Dmitry Baryshkov
2022-05-25 23:58 ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 01/34] phy: qcom-qmp: add library source code Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 02/34] phy: qcom-qmp: add QMP PCIe PHY driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 03/34] phy: qcom-qmp: move MSM8996 PCIe PHY to new QMP driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 04/34] phy: qcom-qmp: move MSM8998 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 05/34] phy: qcom-qmp: move SDM845 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 06/34] phy: qcom-qmp: move SM8250 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 07/34] phy: qcom-qmp: move IPQ6018 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 08/34] phy: qcom-qmp: move IPQ8074 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 09/34] phy: qcom-qmp: move SC8180x " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 10/34] phy: qcom-qmp: move SDX55 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 11/34] phy: qcom-qmp: move SM8450 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` Dmitry Baryshkov [this message]
2022-05-25 23:58   ` [RFC PATCH v2 12/34] phy: qcom-qmp: add QMP UFS PHY driver Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 13/34] phy: qcom-qmp: move MSM8996 UFS PHY to new QMP driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 14/34] phy: qcom-qmp: move MSM8998, SDM845 and SM6350 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 15/34] phy: qcom-qmp: move SC8180x, SM8150 and SM8250 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 16/34] phy: qcom-qmp: move SM6116 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 17/34] phy: qcom-qmp: move SC8280xp, SM8350 and SM8450 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 18/34] phy: qcom-qmp: add QMP USB PHY driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 19/34] phy: qcom-qmp: move MSM8996 USB PHY to new QMP driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 20/34] phy: qcom-qmp: move IPQ6018, IPQ8074 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 21/34] phy: qcom-qmp: move MSM8998 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 22/34] phy: qcom-qmp: move SDM845 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 23/34] phy: qcom-qmp: move SC7180 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 24/34] phy: qcom-qmp: move SC8180x, SM8150 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 25/34] phy: qcom-qmp: move SM8250 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 26/34] phy: qcom-qmp: move SM8350, SM8450 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 27/34] phy: qcom-qmp: move SDX55 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 28/34] phy: qcom-qmp: move SDX65 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 29/34] phy: qcom-qmp: move QCM2290 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 30/34] phy: qcom-qmp: add QMP combo DP+USB PHY driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 31/34] phy: qcom-qmp: move SC7180 DP PHY to new QMP driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 32/34] phy: qcom-qmp: move SC8180X " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 33/34] phy: qcom-qmp: move SM8250 " Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov
2022-05-25 23:58 ` [RFC PATCH v2 34/34] phy: qcom-qmp: drop old QMP PHY driver Dmitry Baryshkov
2022-05-25 23:58   ` Dmitry Baryshkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220525235841.852301-13-dmitry.baryshkov@linaro.org \
    --to=dmitry.baryshkov@linaro.org \
    --cc=agross@kernel.org \
    --cc=bjorn.andersson@linaro.org \
    --cc=kishon@ti.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-phy@lists.infradead.org \
    --cc=p.zabel@pengutronix.de \
    --cc=vkoul@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.