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
next prev 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: linkBe 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.