All of lore.kernel.org
 help / color / mirror / Atom feed
From: Faiz Abbas <faiz_abbas@ti.com>
To: <linux-kernel@vger.kernel.org>, <devicetree@vger.kernel.org>,
	<linux-mmc@vger.kernel.org>
Cc: <kishon@ti.com>, <faiz_abbas@ti.com>, <ulf.hansson@linaro.org>,
	<robh+dt@kernel.org>, <catalin.marinas@arm.com>,
	<adrian.hunter@intel.com>
Subject: [PATCH 2/6] phy: am654-mmc-phy: Add Support for MMC PHY on AM654 Devices
Date: Thu, 4 Oct 2018 16:44:47 +0530	[thread overview]
Message-ID: <20181004111451.9539-3-faiz_abbas@ti.com> (raw)
In-Reply-To: <20181004111451.9539-1-faiz_abbas@ti.com>

Add driver support for the MMC physical layer present
on TI's AM654 devices.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 drivers/phy/ti/Kconfig         |   7 +
 drivers/phy/ti/Makefile        |   1 +
 drivers/phy/ti/phy-am654-mmc.c | 291 +++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 drivers/phy/ti/phy-am654-mmc.c

diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig
index 20503562666c..ea5fe4db01c8 100644
--- a/drivers/phy/ti/Kconfig
+++ b/drivers/phy/ti/Kconfig
@@ -76,3 +76,10 @@ config TWL4030_USB
 	  family chips (including the TWL5030 and TPS659x0 devices).
 	  This transceiver supports high and full speed devices plus,
 	  in host mode, low speed.
+
+config PHY_AM654_MMC
+	bool "TI AM654 MMC PHY Support"
+	select GENERIC_PHY
+	help
+	  This option enables support for the Physical layer for MMC host
+	  controllers present on TI AM654 SOCs.
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile
index 9f361756eaf2..5b2db2d164a5 100644
--- a/drivers/phy/ti/Makefile
+++ b/drivers/phy/ti/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TI_PIPE3)			+= phy-ti-pipe3.o
 obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+obj-$(CONFIG_PHY_AM654_MMC)		+= phy-am654-mmc.o
diff --git a/drivers/phy/ti/phy-am654-mmc.c b/drivers/phy/ti/phy-am654-mmc.c
new file mode 100644
index 000000000000..91255947fb67
--- /dev/null
+++ b/drivers/phy/ti/phy-am654-mmc.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-am654-mmc.c - MMC PHY driver for TI's AM654 SOCs
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+
+/* MMC PHY Registers */
+#define PHYCTRL_CTRL1_REG	0x00
+#define PHYCTRL_CTRL2_REG	0x04
+#define PHYCTRL_CTRL3_REG	0x08
+#define PHYCTRL_CTRL4_REG	0x0C
+#define PHYCTRL_CTRL5_REG	0x10
+#define PHYCTRL_CTRL6_REG	0x14
+#define PHYCTRL_STAT1_REG	0x30
+#define PHYCTRL_STAT2_REG	0x34
+
+#define IOMUX_ENABLE_SHIFT	31
+#define IOMUX_ENABLE_MASK	BIT(IOMUX_ENABLE_SHIFT)
+#define OTAPDLYENA_SHIFT	20
+#define OTAPDLYENA_MASK	BIT(OTAPDLYENA_SHIFT)
+#define OTAPDLYSEL_SHIFT	12
+#define OTAPDLYSEL_MASK	GENMASK(15, 12)
+#define STRBSEL_SHIFT		24
+#define STRBSEL_MASK		GENMASK(27, 24)
+#define SEL50_SHIFT		8
+#define SEL50_MASK		BIT(SEL50_SHIFT)
+#define SEL100_SHIFT		9
+#define SEL100_MASK		BIT(SEL100_SHIFT)
+#define DLL_TRIM_ICP_SHIFT	4
+#define DLL_TRIM_ICP_MASK	GENMASK(7, 4)
+#define DR_TY_SHIFT		20
+#define DR_TY_MASK		GENMASK(22, 20)
+#define ENDLL_SHIFT		1
+#define ENDLL_MASK		BIT(ENDLL_SHIFT)
+#define DLLRDY_SHIFT		0
+#define DLLRDY_MASK		BIT(DLLRDY_SHIFT)
+#define PDB_SHIFT		0
+#define PDB_MASK		BIT(PDB_SHIFT)
+#define CALDONE_SHIFT		1
+#define CALDONE_MASK		BIT(CALDONE_SHIFT)
+
+#define DRIVER_STRENGTH_50_OHM	0x0
+#define DRIVER_STRENGTH_33_OHM	0x1
+#define DRIVER_STRENGTH_66_OHM	0x2
+#define DRIVER_STRENGTH_100_OHM	0x3
+#define DRIVER_STRENGTH_40_OHM	0x4
+
+static struct regmap_config am654_mmc_phy_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.fast_io = true,
+};
+
+struct am654_mmc_phy {
+	struct regmap *reg_base;
+	struct clk *mmcclk;
+	int otap_del_sel;
+	int trm_icp;
+	int drv_strength;
+};
+
+static int am654_mmc_phy_init(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+	int ret;
+	u32 val;
+
+	/* Reset registers to default value */
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL1_REG, 0x10000);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL4_REG, 0x0);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL5_REG, 0x0);
+
+	/* Calibrate IO lines */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   PDB_MASK, PDB_MASK);
+	ret = regmap_read_poll_timeout(mmc_phy->reg_base, PHYCTRL_STAT1_REG,
+				       val, val & CALDONE_MASK, 1, 20);
+	if (ret)
+		return ret;
+
+	/* Enable pins by setting the IO mux to 0 */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   IOMUX_ENABLE_MASK, 0);
+
+	mmc_phy->mmcclk = clk_get(&phy->dev, "mmcclk");
+	if (IS_ERR(mmc_phy->mmcclk)) {
+		dev_err(&phy->dev, "Error getting mmcclk");
+		return PTR_ERR(mmc_phy->mmcclk);
+	}
+
+	return 0;
+}
+
+static int am654_mmc_phy_exit(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+
+	clk_put(mmc_phy->mmcclk);
+
+	return 0;
+}
+
+static int am654_mmc_phy_power_on(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+	u32 mask, val;
+	int sel50, sel100;
+	int rate;
+
+	/* Setup DLL Output TAP delay */
+	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+	val = (1 << OTAPDLYENA_SHIFT) |
+	      (mmc_phy->otap_del_sel << OTAPDLYSEL_SHIFT);
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL4_REG,
+			   mask, val);
+
+	rate = clk_get_rate(mmc_phy->mmcclk);
+	switch (rate) {
+	case 200000000:
+		sel50 = 0;
+		sel100 = 0;
+		break;
+	case 100000000:
+		sel50 = 0;
+		sel100 = 1;
+		break;
+	default:
+		sel50 = 1;
+		sel100 = 0;
+	}
+
+	/* Configure PHY DLL frequency */
+	mask = SEL50_MASK | SEL100_MASK;
+	val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL5_REG,
+			   mask, val);
+
+	/* Configure DLL TRIM */
+	mask = DLL_TRIM_ICP_MASK;
+	val = mmc_phy->trm_icp << DLL_TRIM_ICP_SHIFT;
+
+	/* Configure DLL driver strength */
+	mask |= DR_TY_MASK;
+	val |= mmc_phy->drv_strength << DR_TY_SHIFT;
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG, mask, val);
+
+	/* Enable DLL */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   ENDLL_MASK, 0x1 << ENDLL_SHIFT);
+
+	/*
+	 * Poll for DLL ready. Use a one second timeout.
+	 * Works in all experiments done so far
+	 */
+	return regmap_read_poll_timeout(mmc_phy->reg_base, PHYCTRL_STAT1_REG,
+					val, val & DLLRDY_MASK, 1000, 1000000);
+
+}
+
+static int am654_mmc_phy_power_off(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+
+	/* Disable DLL */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   ENDLL_MASK, 0);
+
+	/* Reset registers to default value except PDB */
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+		     0x10000 | PDB_MASK);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL4_REG, 0x0);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL5_REG, 0x0);
+
+	return 0;
+}
+
+static const struct phy_ops ops = {
+	.init		= am654_mmc_phy_init,
+	.exit		= am654_mmc_phy_exit,
+	.power_on	= am654_mmc_phy_power_on,
+	.power_off	= am654_mmc_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static int am654_mmc_phy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct am654_mmc_phy *mmc_phy;
+	struct phy *generic_phy;
+	struct resource *res;
+	void __iomem *base;
+	struct regmap *map;
+	int drv_strength;
+	int err;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	map = devm_regmap_init_mmio(dev, base, &am654_mmc_phy_regmap_config);
+	if (IS_ERR(map)) {
+		dev_err(dev, "could not initialize regmap\n");
+		return PTR_ERR(map);
+	}
+
+	mmc_phy = devm_kzalloc(dev, sizeof(struct am654_mmc_phy), GFP_KERNEL);
+	if (!mmc_phy)
+		return -ENOMEM;
+
+	mmc_phy->reg_base = map;
+	err = of_property_read_u32(np, "ti,otap-del-sel",
+				   &mmc_phy->otap_del_sel);
+	if (err)
+		return err;
+
+	err = of_property_read_u32(np, "ti,trm-icp",
+				   &mmc_phy->trm_icp);
+	if (err)
+		return err;
+
+	err = of_property_read_u32(np, "ti,driver-strength-ohm", &drv_strength);
+	if (err)
+		return err;
+
+	switch (drv_strength) {
+	case 50:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_50_OHM;
+		break;
+	case 33:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_33_OHM;
+		break;
+	case 66:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_66_OHM;
+		break;
+	case 100:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_100_OHM;
+		break;
+	case 40:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_40_OHM;
+		break;
+	default:
+		dev_err(dev, "Invalid driver strength\n");
+		return -EINVAL;
+	}
+
+	generic_phy = devm_phy_create(dev, dev->of_node, &ops);
+	if (IS_ERR(generic_phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(generic_phy);
+	}
+
+	phy_set_drvdata(generic_phy, mmc_phy);
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id am654_mmc_phy_dt_ids[] = {
+	{ .compatible = "ti,am654-mmc-phy" },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, am654_mmc_phy_dt_ids);
+
+static struct platform_driver am654_mmc_phy_driver = {
+	.probe		= am654_mmc_phy_probe,
+	.driver		= {
+		.name	= "am654-mmc-phy",
+		.of_match_table = am654_mmc_phy_dt_ids,
+	},
+};
+
+module_platform_driver(am654_mmc_phy_driver);
+
+MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>");
+MODULE_DESCRIPTION("TI AM654 MMC PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.18.0


WARNING: multiple messages have this Message-ID (diff)
From: Faiz Abbas <faiz_abbas@ti.com>
To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org,
	linux-mmc@vger.kernel.org
Cc: kishon@ti.com, faiz_abbas@ti.com, ulf.hansson@linaro.org,
	robh+dt@kernel.org, catalin.marinas@arm.com,
	adrian.hunter@intel.com
Subject: [PATCH 2/6] phy: am654-mmc-phy: Add Support for MMC PHY on AM654 Devices
Date: Thu, 4 Oct 2018 16:44:47 +0530	[thread overview]
Message-ID: <20181004111451.9539-3-faiz_abbas@ti.com> (raw)
In-Reply-To: <20181004111451.9539-1-faiz_abbas@ti.com>

Add driver support for the MMC physical layer present
on TI's AM654 devices.

Signed-off-by: Faiz Abbas <faiz_abbas@ti.com>
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
---
 drivers/phy/ti/Kconfig         |   7 +
 drivers/phy/ti/Makefile        |   1 +
 drivers/phy/ti/phy-am654-mmc.c | 291 +++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 drivers/phy/ti/phy-am654-mmc.c

diff --git a/drivers/phy/ti/Kconfig b/drivers/phy/ti/Kconfig
index 20503562666c..ea5fe4db01c8 100644
--- a/drivers/phy/ti/Kconfig
+++ b/drivers/phy/ti/Kconfig
@@ -76,3 +76,10 @@ config TWL4030_USB
 	  family chips (including the TWL5030 and TPS659x0 devices).
 	  This transceiver supports high and full speed devices plus,
 	  in host mode, low speed.
+
+config PHY_AM654_MMC
+	bool "TI AM654 MMC PHY Support"
+	select GENERIC_PHY
+	help
+	  This option enables support for the Physical layer for MMC host
+	  controllers present on TI AM654 SOCs.
diff --git a/drivers/phy/ti/Makefile b/drivers/phy/ti/Makefile
index 9f361756eaf2..5b2db2d164a5 100644
--- a/drivers/phy/ti/Makefile
+++ b/drivers/phy/ti/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_OMAP_USB2)			+= phy-omap-usb2.o
 obj-$(CONFIG_TI_PIPE3)			+= phy-ti-pipe3.o
 obj-$(CONFIG_PHY_TUSB1210)		+= phy-tusb1210.o
 obj-$(CONFIG_TWL4030_USB)		+= phy-twl4030-usb.o
+obj-$(CONFIG_PHY_AM654_MMC)		+= phy-am654-mmc.o
diff --git a/drivers/phy/ti/phy-am654-mmc.c b/drivers/phy/ti/phy-am654-mmc.c
new file mode 100644
index 000000000000..91255947fb67
--- /dev/null
+++ b/drivers/phy/ti/phy-am654-mmc.c
@@ -0,0 +1,291 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * phy-am654-mmc.c - MMC PHY driver for TI's AM654 SOCs
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+
+/* MMC PHY Registers */
+#define PHYCTRL_CTRL1_REG	0x00
+#define PHYCTRL_CTRL2_REG	0x04
+#define PHYCTRL_CTRL3_REG	0x08
+#define PHYCTRL_CTRL4_REG	0x0C
+#define PHYCTRL_CTRL5_REG	0x10
+#define PHYCTRL_CTRL6_REG	0x14
+#define PHYCTRL_STAT1_REG	0x30
+#define PHYCTRL_STAT2_REG	0x34
+
+#define IOMUX_ENABLE_SHIFT	31
+#define IOMUX_ENABLE_MASK	BIT(IOMUX_ENABLE_SHIFT)
+#define OTAPDLYENA_SHIFT	20
+#define OTAPDLYENA_MASK	BIT(OTAPDLYENA_SHIFT)
+#define OTAPDLYSEL_SHIFT	12
+#define OTAPDLYSEL_MASK	GENMASK(15, 12)
+#define STRBSEL_SHIFT		24
+#define STRBSEL_MASK		GENMASK(27, 24)
+#define SEL50_SHIFT		8
+#define SEL50_MASK		BIT(SEL50_SHIFT)
+#define SEL100_SHIFT		9
+#define SEL100_MASK		BIT(SEL100_SHIFT)
+#define DLL_TRIM_ICP_SHIFT	4
+#define DLL_TRIM_ICP_MASK	GENMASK(7, 4)
+#define DR_TY_SHIFT		20
+#define DR_TY_MASK		GENMASK(22, 20)
+#define ENDLL_SHIFT		1
+#define ENDLL_MASK		BIT(ENDLL_SHIFT)
+#define DLLRDY_SHIFT		0
+#define DLLRDY_MASK		BIT(DLLRDY_SHIFT)
+#define PDB_SHIFT		0
+#define PDB_MASK		BIT(PDB_SHIFT)
+#define CALDONE_SHIFT		1
+#define CALDONE_MASK		BIT(CALDONE_SHIFT)
+
+#define DRIVER_STRENGTH_50_OHM	0x0
+#define DRIVER_STRENGTH_33_OHM	0x1
+#define DRIVER_STRENGTH_66_OHM	0x2
+#define DRIVER_STRENGTH_100_OHM	0x3
+#define DRIVER_STRENGTH_40_OHM	0x4
+
+static struct regmap_config am654_mmc_phy_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
+	.fast_io = true,
+};
+
+struct am654_mmc_phy {
+	struct regmap *reg_base;
+	struct clk *mmcclk;
+	int otap_del_sel;
+	int trm_icp;
+	int drv_strength;
+};
+
+static int am654_mmc_phy_init(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+	int ret;
+	u32 val;
+
+	/* Reset registers to default value */
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL1_REG, 0x10000);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL4_REG, 0x0);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL5_REG, 0x0);
+
+	/* Calibrate IO lines */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   PDB_MASK, PDB_MASK);
+	ret = regmap_read_poll_timeout(mmc_phy->reg_base, PHYCTRL_STAT1_REG,
+				       val, val & CALDONE_MASK, 1, 20);
+	if (ret)
+		return ret;
+
+	/* Enable pins by setting the IO mux to 0 */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   IOMUX_ENABLE_MASK, 0);
+
+	mmc_phy->mmcclk = clk_get(&phy->dev, "mmcclk");
+	if (IS_ERR(mmc_phy->mmcclk)) {
+		dev_err(&phy->dev, "Error getting mmcclk");
+		return PTR_ERR(mmc_phy->mmcclk);
+	}
+
+	return 0;
+}
+
+static int am654_mmc_phy_exit(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+
+	clk_put(mmc_phy->mmcclk);
+
+	return 0;
+}
+
+static int am654_mmc_phy_power_on(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+	u32 mask, val;
+	int sel50, sel100;
+	int rate;
+
+	/* Setup DLL Output TAP delay */
+	mask = OTAPDLYENA_MASK | OTAPDLYSEL_MASK;
+	val = (1 << OTAPDLYENA_SHIFT) |
+	      (mmc_phy->otap_del_sel << OTAPDLYSEL_SHIFT);
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL4_REG,
+			   mask, val);
+
+	rate = clk_get_rate(mmc_phy->mmcclk);
+	switch (rate) {
+	case 200000000:
+		sel50 = 0;
+		sel100 = 0;
+		break;
+	case 100000000:
+		sel50 = 0;
+		sel100 = 1;
+		break;
+	default:
+		sel50 = 1;
+		sel100 = 0;
+	}
+
+	/* Configure PHY DLL frequency */
+	mask = SEL50_MASK | SEL100_MASK;
+	val = (sel50 << SEL50_SHIFT) | (sel100 << SEL100_SHIFT);
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL5_REG,
+			   mask, val);
+
+	/* Configure DLL TRIM */
+	mask = DLL_TRIM_ICP_MASK;
+	val = mmc_phy->trm_icp << DLL_TRIM_ICP_SHIFT;
+
+	/* Configure DLL driver strength */
+	mask |= DR_TY_MASK;
+	val |= mmc_phy->drv_strength << DR_TY_SHIFT;
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG, mask, val);
+
+	/* Enable DLL */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   ENDLL_MASK, 0x1 << ENDLL_SHIFT);
+
+	/*
+	 * Poll for DLL ready. Use a one second timeout.
+	 * Works in all experiments done so far
+	 */
+	return regmap_read_poll_timeout(mmc_phy->reg_base, PHYCTRL_STAT1_REG,
+					val, val & DLLRDY_MASK, 1000, 1000000);
+
+}
+
+static int am654_mmc_phy_power_off(struct phy *phy)
+{
+	struct am654_mmc_phy *mmc_phy = phy_get_drvdata(phy);
+
+	/* Disable DLL */
+	regmap_update_bits(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+			   ENDLL_MASK, 0);
+
+	/* Reset registers to default value except PDB */
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL1_REG,
+		     0x10000 | PDB_MASK);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL4_REG, 0x0);
+	regmap_write(mmc_phy->reg_base, PHYCTRL_CTRL5_REG, 0x0);
+
+	return 0;
+}
+
+static const struct phy_ops ops = {
+	.init		= am654_mmc_phy_init,
+	.exit		= am654_mmc_phy_exit,
+	.power_on	= am654_mmc_phy_power_on,
+	.power_off	= am654_mmc_phy_power_off,
+	.owner		= THIS_MODULE,
+};
+
+static int am654_mmc_phy_probe(struct platform_device *pdev)
+{
+	struct phy_provider *phy_provider;
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct am654_mmc_phy *mmc_phy;
+	struct phy *generic_phy;
+	struct resource *res;
+	void __iomem *base;
+	struct regmap *map;
+	int drv_strength;
+	int err;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	base = devm_ioremap_resource(&pdev->dev, res);
+	if (IS_ERR(base))
+		return PTR_ERR(base);
+
+	map = devm_regmap_init_mmio(dev, base, &am654_mmc_phy_regmap_config);
+	if (IS_ERR(map)) {
+		dev_err(dev, "could not initialize regmap\n");
+		return PTR_ERR(map);
+	}
+
+	mmc_phy = devm_kzalloc(dev, sizeof(struct am654_mmc_phy), GFP_KERNEL);
+	if (!mmc_phy)
+		return -ENOMEM;
+
+	mmc_phy->reg_base = map;
+	err = of_property_read_u32(np, "ti,otap-del-sel",
+				   &mmc_phy->otap_del_sel);
+	if (err)
+		return err;
+
+	err = of_property_read_u32(np, "ti,trm-icp",
+				   &mmc_phy->trm_icp);
+	if (err)
+		return err;
+
+	err = of_property_read_u32(np, "ti,driver-strength-ohm", &drv_strength);
+	if (err)
+		return err;
+
+	switch (drv_strength) {
+	case 50:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_50_OHM;
+		break;
+	case 33:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_33_OHM;
+		break;
+	case 66:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_66_OHM;
+		break;
+	case 100:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_100_OHM;
+		break;
+	case 40:
+		mmc_phy->drv_strength = DRIVER_STRENGTH_40_OHM;
+		break;
+	default:
+		dev_err(dev, "Invalid driver strength\n");
+		return -EINVAL;
+	}
+
+	generic_phy = devm_phy_create(dev, dev->of_node, &ops);
+	if (IS_ERR(generic_phy)) {
+		dev_err(dev, "failed to create PHY\n");
+		return PTR_ERR(generic_phy);
+	}
+
+	phy_set_drvdata(generic_phy, mmc_phy);
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id am654_mmc_phy_dt_ids[] = {
+	{ .compatible = "ti,am654-mmc-phy" },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, am654_mmc_phy_dt_ids);
+
+static struct platform_driver am654_mmc_phy_driver = {
+	.probe		= am654_mmc_phy_probe,
+	.driver		= {
+		.name	= "am654-mmc-phy",
+		.of_match_table = am654_mmc_phy_dt_ids,
+	},
+};
+
+module_platform_driver(am654_mmc_phy_driver);
+
+MODULE_AUTHOR("Faiz Abbas <faiz_abbas@ti.com>");
+MODULE_DESCRIPTION("TI AM654 MMC PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.18.0

  parent reply	other threads:[~2018-10-04 11:13 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-10-04 11:14 [PATCH 0/6] Add Support for MMC/SD in TI's AM65x SOCs Faiz Abbas
2018-10-04 11:14 ` Faiz Abbas
2018-10-04 11:14 ` [PATCH 1/6] dt-bindings: phy: am654-mmc-phy: Document new phy bindings Faiz Abbas
2018-10-04 11:14   ` Faiz Abbas
2018-10-05 15:58   ` Andrew F. Davis
2018-10-05 15:58     ` Andrew F. Davis
2018-10-09  6:34     ` Faiz Abbas
2018-10-09  6:34       ` Faiz Abbas
2018-10-08 11:29   ` Ulf Hansson
2018-10-04 11:14 ` Faiz Abbas [this message]
2018-10-04 11:14   ` [PATCH 2/6] phy: am654-mmc-phy: Add Support for MMC PHY on AM654 Devices Faiz Abbas
2018-10-08 11:32   ` Ulf Hansson
2018-10-09  5:18     ` Kishon Vijay Abraham I
2018-10-09  7:30       ` Ulf Hansson
2018-10-04 11:14 ` [PATCH 3/6] dt-bindings: mmc: sdhci-of-arasan: Add new compatible for AM654 MMC PHY Faiz Abbas
2018-10-04 11:14   ` Faiz Abbas
2018-10-09  7:30   ` Ulf Hansson
2018-10-04 11:14 ` [PATCH 4/6] mmc: sdhci-of-arasan: Add a single data structure to incorporate pdata and soc_ctl_map Faiz Abbas
2018-10-04 11:14   ` Faiz Abbas
2018-10-09  7:30   ` Ulf Hansson
2018-10-04 11:14 ` [PATCH 5/6] mmc: sdhci-of-arasan: Add Support for AM654 MMC and PHY Faiz Abbas
2018-10-04 11:14   ` Faiz Abbas
2018-10-09  7:30   ` Ulf Hansson
2018-10-09  7:35     ` Faiz Abbas
2018-10-09  7:35       ` Ulf Hansson
2018-10-04 11:14 ` [PATCH 6/6] arm64: defconfig: Enable MMC PHY for AM65xx Faiz Abbas
2018-10-04 11:14   ` Faiz Abbas

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=20181004111451.9539-3-faiz_abbas@ti.com \
    --to=faiz_abbas@ti.com \
    --cc=adrian.hunter@intel.com \
    --cc=catalin.marinas@arm.com \
    --cc=devicetree@vger.kernel.org \
    --cc=kishon@ti.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mmc@vger.kernel.org \
    --cc=robh+dt@kernel.org \
    --cc=ulf.hansson@linaro.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.