From 15f6bc7c3da92701c25959e80d76eadecc927123 Mon Sep 17 00:00:00 2001 From: Sneh Shah Date: Mon, 10 Jun 2019 18:11:50 +0530 Subject: [PATCH] net: stmmac: SDx55 EMAC HW configuration changes Add RGMII config and regulator support for EMAC HW configuration on SDx55. Change-Id: I7b1cd3bcb7c78f5fa1c684d2523a41c51da72998 Acked-by: Suraj Jaiswal Acked-by: Nagarjuna Chaganti Signed-off-by: Sneh Shah --- drivers/net/ethernet/stmicro/stmmac/Makefile | 1 + .../stmicro/stmmac/dwmac-qcom-ethqos.c | 171 ++++++++++-------- .../stmicro/stmmac/dwmac-qcom-ethqos.h | 66 +++++++ .../ethernet/stmicro/stmmac/dwmac-qcom-gpio.c | 129 +++++++++++++ 4 files changed, 288 insertions(+), 79 deletions(-) create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h create mode 100644 drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile index c59926d96bcc..005cc7baca52 100644 --- a/drivers/net/ethernet/stmicro/stmmac/Makefile +++ b/drivers/net/ethernet/stmicro/stmmac/Makefile @@ -18,6 +18,7 @@ obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o obj-$(CONFIG_DWMAC_MEDIATEK) += dwmac-mediatek.o obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o dwmac-meson8b.o obj-$(CONFIG_DWMAC_OXNAS) += dwmac-oxnas.o +obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-gpio.o obj-$(CONFIG_DWMAC_QCOM_ETHQOS) += dwmac-qcom-ethqos.o obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-altr-socfpga.o diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c index bfc4a92f1d92..d5e98c9f10c9 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.c @@ -6,16 +6,12 @@ #include #include #include +#include + #include "stmmac.h" #include "stmmac_platform.h" +#include "dwmac-qcom-ethqos.h" -#define RGMII_IO_MACRO_CONFIG 0x0 -#define SDCC_HC_REG_DLL_CONFIG 0x4 -#define SDCC_HC_REG_DDR_CONFIG 0xC -#define SDCC_HC_REG_DLL_CONFIG2 0x10 -#define SDC4_STATUS 0x14 -#define SDCC_USR_CTL 0x18 -#define RGMII_IO_MACRO_CONFIG2 0x1C #define RGMII_IO_MACRO_DEBUG1 0x20 #define EMAC_SYSTEM_LOW_POWER_DEBUG 0x28 @@ -70,27 +66,8 @@ #define RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL BIT(6) #define RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN BIT(5) -struct ethqos_emac_por { - unsigned int offset; - unsigned int value; -}; - -struct ethqos_emac_driver_data { - const struct ethqos_emac_por *por; - unsigned int num_por; -}; - -struct qcom_ethqos { - struct platform_device *pdev; - void __iomem *rgmii_base; - - unsigned int rgmii_clk_rate; - struct clk *rgmii_clk; - unsigned int speed; - - const struct ethqos_emac_por *por; - unsigned int num_por; -}; +#define EMAC_I0_EMAC_CORE_HW_VERSION_RGOFFADDR 0x00000070 +#define EMAC_HW_v2_3_2_RG 0x20030002 static int rgmii_readl(struct qcom_ethqos *ethqos, unsigned int offset) { @@ -167,28 +144,18 @@ static void ethqos_set_func_clk_en(struct qcom_ethqos *ethqos) RGMII_CONFIG_FUNC_CLK_EN, RGMII_IO_MACRO_CONFIG); } -static const struct ethqos_emac_por emac_v2_3_0_por[] = { - { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, - { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, - { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, - { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, - { .offset = SDCC_USR_CTL, .value = 0x00010800 }, - { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, -}; - -static const struct ethqos_emac_driver_data emac_v2_3_0_data = { - .por = emac_v2_3_0_por, - .num_por = ARRAY_SIZE(emac_v2_3_0_por), -}; - static int ethqos_dll_configure(struct qcom_ethqos *ethqos) { unsigned int val; int retry = 1000; /* Set CDR_EN */ - rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, - SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, + 0, SDCC_HC_REG_DLL_CONFIG); + else + rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EN, + SDCC_DLL_CONFIG_CDR_EN, SDCC_HC_REG_DLL_CONFIG); /* Set CDR_EXT_EN */ rgmii_updatel(ethqos, SDCC_DLL_CONFIG_CDR_EXT_EN, @@ -202,12 +169,13 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG_DLL_EN, SDCC_DLL_CONFIG_DLL_EN, SDCC_HC_REG_DLL_CONFIG); - rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, - 0, SDCC_HC_REG_DLL_CONFIG); - - rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, - 0, SDCC_HC_REG_DLL_CONFIG); + if (ethqos->emac_ver != EMAC_HW_v2_3_2_RG) { + rgmii_updatel(ethqos, SDCC_DLL_MCLK_GATING_EN, + 0, SDCC_HC_REG_DLL_CONFIG); + rgmii_updatel(ethqos, SDCC_DLL_CDR_FINE_PHASE, + 0, SDCC_HC_REG_DLL_CONFIG); + } /* Wait for CK_OUT_EN clear */ do { val = rgmii_readl(ethqos, SDCC_HC_REG_DLL_CONFIG); @@ -241,18 +209,20 @@ static int ethqos_dll_configure(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_DLL_CONFIG2_DDR_CAL_EN, SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, - 0, SDCC_HC_REG_DLL_CONFIG2); + if (ethqos->emac_ver != EMAC_HW_v2_3_2_RG) { + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DLL_CLOCK_DIS, + 0, SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, - 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_MCLK_FREQ_CALC, + 0x1A << 10, SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, - BIT(2), SDCC_HC_REG_DLL_CONFIG2); + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SEL, + BIT(2), SDCC_HC_REG_DLL_CONFIG2); - rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, - SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, - SDCC_HC_REG_DLL_CONFIG2); + rgmii_updatel(ethqos, SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, + SDCC_DLL_CONFIG2_DDR_TRAFFIC_INIT_SW, + SDCC_HC_REG_DLL_CONFIG2); + } return 0; } @@ -290,13 +260,22 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) RGMII_IO_MACRO_CONFIG2); /* Set PRG_RCLK_DLY to 57 for 1.8 ns delay */ - rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, - 57, SDCC_HC_REG_DDR_CONFIG); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 69, SDCC_HC_REG_DDR_CONFIG); + else + rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_RCLK_DLY, + 57, SDCC_HC_REG_DDR_CONFIG); rgmii_updatel(ethqos, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_DDR_CONFIG_PRG_DLY_EN, SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, - RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + 0, RGMII_IO_MACRO_CONFIG); + else + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + RGMII_CONFIG_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG); break; case SPEED_100: @@ -318,8 +297,13 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) BIT(6), RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); + else + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + 0, RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); @@ -329,8 +313,13 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, - RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + 0, RGMII_IO_MACRO_CONFIG); + else + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + RGMII_CONFIG_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG); break; case SPEED_10: @@ -345,15 +334,27 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) 0, RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_DATA_DIVIDE_CLK_SEL, 0, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, - 0, RGMII_IO_MACRO_CONFIG2); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, + RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, + RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, + RGMII_IO_MACRO_CONFIG2); + else + rgmii_updatel(ethqos, + RGMII_CONFIG2_TX_CLK_PHASE_SHIFT_EN, + 0, RGMII_IO_MACRO_CONFIG2); rgmii_updatel(ethqos, RGMII_CONFIG_MAX_SPD_PRG_9, BIT(12) | GENMASK(9, 8), RGMII_IO_MACRO_CONFIG); rgmii_updatel(ethqos, RGMII_CONFIG2_RSVD_CONFIG15, 0, RGMII_IO_MACRO_CONFIG2); - rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, - 0, RGMII_IO_MACRO_CONFIG2); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_CONFIG2_RX_PROG_SWAP, + RGMII_IO_MACRO_CONFIG2); + else + rgmii_updatel(ethqos, RGMII_CONFIG2_RX_PROG_SWAP, + 0, RGMII_IO_MACRO_CONFIG2); /* Write 0x5 to PRG_RCLK_DLY_CODE */ rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_CODE, (BIT(29) | BIT(27)), SDCC_HC_REG_DDR_CONFIG); @@ -363,8 +364,13 @@ static int ethqos_rgmii_macro_init(struct qcom_ethqos *ethqos) rgmii_updatel(ethqos, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, SDCC_DDR_CONFIG_EXT_PRG_RCLK_DLY_EN, SDCC_HC_REG_DDR_CONFIG); - rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, - RGMII_CONFIG_LOOPBACK_EN, RGMII_IO_MACRO_CONFIG); + if (ethqos->emac_ver == EMAC_HW_v2_3_2_RG) + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + 0, RGMII_IO_MACRO_CONFIG); + else + rgmii_updatel(ethqos, RGMII_CONFIG_LOOPBACK_EN, + RGMII_CONFIG_LOOPBACK_EN, + RGMII_IO_MACRO_CONFIG); break; default: dev_err(ðqos->pdev->dev, @@ -461,19 +467,21 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) return ret; + ethqos = devm_kzalloc(&pdev->dev, sizeof(*ethqos), GFP_KERNEL); + if (!ethqos) { + ret = -ENOMEM; + goto err_mem; + } + ethqos->pdev = pdev; + + ethqos_init_reqgulators(ethqos); plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac); if (IS_ERR(plat_dat)) { dev_err(&pdev->dev, "dt configuration failed\n"); return PTR_ERR(plat_dat); } - ethqos = devm_kzalloc(&pdev->dev, sizeof(*ethqos), GFP_KERNEL); - if (!ethqos) { - ret = -ENOMEM; - goto err_mem; - } - ethqos->pdev = pdev; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rgmii"); ethqos->rgmii_base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(ethqos->rgmii_base)) { @@ -510,6 +518,9 @@ static int qcom_ethqos_probe(struct platform_device *pdev) if (ret) goto err_clk; + ethqos->emac_ver = rgmii_readl(ethqos, + EMAC_I0_EMAC_CORE_HW_VERSION_RGOFFADDR); + rgmii_dump(ethqos); return ret; @@ -534,12 +545,14 @@ static int qcom_ethqos_remove(struct platform_device *pdev) ret = stmmac_pltfr_remove(pdev); clk_disable_unprepare(ethqos->rgmii_clk); + ethqos_disable_regulators(ethqos); return ret; } static const struct of_device_id qcom_ethqos_match[] = { - { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_data}, + { .compatible = "qcom,qcs404-ethqos", .data = &emac_v2_3_0_por}, + { .compatible = "qcom,sdxprairie-ethqos", .data = &emac_v2_3_2_por}, { } }; MODULE_DEVICE_TABLE(of, qcom_ethqos_match); diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h new file mode 100644 index 000000000000..544f7c72fbd0 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-ethqos.h @@ -0,0 +1,66 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ +#ifndef _DWMAC_QCOM_ETHQOS_H +#define _DWMAC_QCOM_ETHQOS_H + +#define DRV_NAME "qcom-ethqos" +#define ETHQOSDBG(fmt, args...) \ + pr_debug(DRV_NAME " %s:%d " fmt, __func__, ## args) +#define ETHQOSERR(fmt, args...) \ + pr_err(DRV_NAME " %s:%d " fmt, __func__, ## args) +#define ETHQOSINFO(fmt, args...) \ + pr_info(DRV_NAME " %s:%d " fmt, __func__, ## args) + +#define RGMII_IO_MACRO_CONFIG 0x0 +#define SDCC_HC_REG_DLL_CONFIG 0x4 +#define SDCC_HC_REG_DDR_CONFIG 0xC +#define SDCC_HC_REG_DLL_CONFIG2 0x10 +#define SDC4_STATUS 0x14 +#define SDCC_USR_CTL 0x18 +#define RGMII_IO_MACRO_CONFIG2 0x1C + +struct ethqos_emac_por { + unsigned int offset; + unsigned int value; +}; + +static const struct ethqos_emac_por emac_v2_3_0_por[] = { + { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, + { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, + { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x00000000 }, + { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, + { .offset = SDCC_USR_CTL, .value = 0x00010800 }, + { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, +}; + +static const struct ethqos_emac_por emac_v2_3_2_por[] = { + { .offset = RGMII_IO_MACRO_CONFIG, .value = 0x00C01343 }, + { .offset = SDCC_HC_REG_DLL_CONFIG, .value = 0x2004642C }, + { .offset = SDCC_HC_REG_DDR_CONFIG, .value = 0x80040800 }, + { .offset = SDCC_HC_REG_DLL_CONFIG2, .value = 0x00200000 }, + { .offset = SDCC_USR_CTL, .value = 0x00010800 }, + { .offset = RGMII_IO_MACRO_CONFIG2, .value = 0x00002060 }, +}; + +struct qcom_ethqos { + struct platform_device *pdev; + void __iomem *rgmii_base; + + unsigned int rgmii_clk_rate; + struct clk *rgmii_clk; + unsigned int speed; + + const struct ethqos_emac_por *por; + unsigned int num_por; + unsigned int emac_ver; + + struct regulator *gdsc_emac; + struct regulator *reg_rgmii; + struct regulator *reg_emac_phy; + struct regulator *reg_rgmii_io_pads; +}; + +int ethqos_init_reqgulators(struct qcom_ethqos *ethqos); +void ethqos_disable_regulators(struct qcom_ethqos *ethqos); +#endif diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c new file mode 100644 index 000000000000..b9c73446ba99 --- /dev/null +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-qcom-gpio.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (c) 2021, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include + +#include "stmmac.h" +#include "dwmac-qcom-ethqos.h" + +#define EMAC_GDSC_EMAC_NAME "gdsc_emac" +#define EMAC_VREG_RGMII_NAME "vreg_rgmii" +#define EMAC_VREG_EMAC_PHY_NAME "vreg_emac_phy" +#define EMAC_VREG_RGMII_IO_PADS_NAME "vreg_rgmii_io_pads" + +int ethqos_init_reqgulators(struct qcom_ethqos *ethqos) +{ + int ret = 0; + + if (of_property_read_bool(ethqos->pdev->dev.of_node, + "gdsc_emac-supply")) { + ethqos->gdsc_emac = + devm_regulator_get(ðqos->pdev->dev, EMAC_GDSC_EMAC_NAME); + if (IS_ERR(ethqos->gdsc_emac)) { + ETHQOSERR("Can not get <%s>\n", EMAC_GDSC_EMAC_NAME); + return PTR_ERR(ethqos->gdsc_emac); + } + + ret = regulator_enable(ethqos->gdsc_emac); + if (ret) { + ETHQOSERR("Can not enable <%s>\n", EMAC_GDSC_EMAC_NAME); + goto reg_error; + } + + ETHQOSDBG("Enabled <%s>\n", EMAC_GDSC_EMAC_NAME); + } + + if (of_property_read_bool(ethqos->pdev->dev.of_node, + "vreg_rgmii-supply")) { + ethqos->reg_rgmii = + devm_regulator_get(ðqos->pdev->dev, EMAC_VREG_RGMII_NAME); + if (IS_ERR(ethqos->reg_rgmii)) { + ETHQOSERR("Can not get <%s>\n", EMAC_VREG_RGMII_NAME); + return PTR_ERR(ethqos->reg_rgmii); + } + + ret = regulator_enable(ethqos->reg_rgmii); + if (ret) { + ETHQOSERR("Can not enable <%s>\n", + EMAC_VREG_RGMII_NAME); + goto reg_error; + } + + ETHQOSDBG("Enabled <%s>\n", EMAC_VREG_RGMII_NAME); + } + + if (of_property_read_bool(ethqos->pdev->dev.of_node, + "vreg_emac_phy-supply")) { + ethqos->reg_emac_phy = + devm_regulator_get(ðqos->pdev->dev, EMAC_VREG_EMAC_PHY_NAME); + if (IS_ERR(ethqos->reg_emac_phy)) { + ETHQOSERR("Can not get <%s>\n", + EMAC_VREG_EMAC_PHY_NAME); + return PTR_ERR(ethqos->reg_emac_phy); + } + + ret = regulator_enable(ethqos->reg_emac_phy); + if (ret) { + ETHQOSERR("Can not enable <%s>\n", + EMAC_VREG_EMAC_PHY_NAME); + goto reg_error; + } + + ETHQOSDBG("Enabled <%s>\n", EMAC_VREG_EMAC_PHY_NAME); + } + + if (of_property_read_bool(ethqos->pdev->dev.of_node, + "vreg_rgmii_io_pads-supply")) { + ethqos->reg_rgmii_io_pads = devm_regulator_get + (ðqos->pdev->dev, EMAC_VREG_RGMII_IO_PADS_NAME); + if (IS_ERR(ethqos->reg_rgmii_io_pads)) { + ETHQOSERR("Can not get <%s>\n", + EMAC_VREG_RGMII_IO_PADS_NAME); + return PTR_ERR(ethqos->reg_rgmii_io_pads); + } + + ret = regulator_enable(ethqos->reg_rgmii_io_pads); + if (ret) { + ETHQOSERR("Can not enable <%s>\n", + EMAC_VREG_RGMII_IO_PADS_NAME); + goto reg_error; + } + + ETHQOSDBG("Enabled <%s>\n", EMAC_VREG_RGMII_IO_PADS_NAME); + } + + return ret; + +reg_error: + ETHQOSERR("%s failed\n", __func__); + ethqos_disable_regulators(ethqos); + return ret; +} + +void ethqos_disable_regulators(struct qcom_ethqos *ethqos) +{ + if (ethqos->reg_rgmii) { + regulator_disable(ethqos->reg_rgmii); + ethqos->reg_rgmii = NULL; + } + + if (ethqos->reg_emac_phy) { + regulator_disable(ethqos->reg_emac_phy); + ethqos->reg_emac_phy = NULL; + } + + if (ethqos->reg_rgmii_io_pads) { + regulator_disable(ethqos->reg_rgmii_io_pads); + ethqos->reg_rgmii_io_pads = NULL; + } + + if (ethqos->gdsc_emac) { + regulator_disable(ethqos->gdsc_emac); + ethqos->gdsc_emac = NULL; + } +}