Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bd39df57 authored by Alok Chauhan's avatar Alok Chauhan
Browse files

msm: emac: enable regulator support in EMAC



Emac controller needs optional regulator to be enabled
for some platforms for EMAC controller.

Add regulator support in EMAC driver.

Change-Id: Ie3c2c96acb50a680788c0b3fb30bbb67cec5abe4
Signed-off-by: default avatarAlok Chauhan <alokc@codeaurora.org>
parent acb74895
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -38,6 +38,13 @@
/* mdio/mdc gpios */
#define EMAC_GPIO_CNT         2

enum emac_vreg_id {
	EMAC_VREG1,
	EMAC_VREG2,
	EMAC_VREG3,
	EMAC_VREG_CNT
};

enum emac_clk_id {
	EMAC_CLK_AXI,
	EMAC_CLK_CFG_AHB,
@@ -575,6 +582,12 @@ struct emac_clk {
	bool			enabled;
};

struct emac_regulator {
	struct regulator *vreg;
	bool			enabled;
	bool			set_voltage;
};

/* emac_ring_header represents a single, contiguous block of DMA space
 * mapped for the three descriptor rings (tpd, rfd, rrd)
 */
@@ -704,6 +717,7 @@ struct emac_adapter {
	struct emac_irq_per_dev		irq[EMAC_IRQ_CNT];
	unsigned int			gpio[EMAC_GPIO_CNT];
	struct emac_clk			clk[EMAC_CLK_CNT];
	struct emac_regulator		vreg[EMAC_VREG_CNT];

	/* dma parameters */
	u64                             dma_mask;
+131 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/tcp.h>
#include <linux/regulator/consumer.h>
#include <net/ip6_checksum.h>

#include "emac.h"
@@ -65,6 +66,10 @@ const char emac_drv_version[] = DRV_VERSION;
#define EMAC_PINCTRL_STATE_ACTIVE "emac_active"
#define EMAC_PINCTRL_STATE_SLEEP "emac_sleep"

#define EMAC_VREG1_VOLTAGE	1250000
#define EMAC_VREG2_VOLTAGE	2850000
#define EMAC_VREG_RESET_VOLTAGE	0

struct emac_skb_cb {
	u32           tpd_idx;
	unsigned long jiffies;
@@ -117,6 +122,10 @@ static const char * const emac_clk_name[] = {
	"sys_clk"
};

static const char * const emac_regulator_name[] = {
	"emac_vreg1", "emac_vreg2", "emac_vreg3"
};

static int emac_clk_prepare_enable(struct emac_adapter *adpt,
				   enum emac_clk_id id)
{
@@ -2668,6 +2677,121 @@ static void emac_release_resources(struct emac_adapter *adpt)
	}
}

/* Get the regulator */
static int emac_get_regulator(struct platform_device *pdev,
			      struct emac_adapter *adpt)
{
	struct regulator *vreg;
	u8 i;

	for (i = 0; i < EMAC_VREG_CNT; i++) {
		vreg = devm_regulator_get(&pdev->dev, emac_regulator_name[i]);

		if (IS_ERR(vreg)) {
			emac_dbg(adpt, probe, "error:%ld unable to get emac %s\n",
				 PTR_ERR(vreg), emac_regulator_name[i]);
			return PTR_ERR(vreg);
		}
		adpt->vreg[i].vreg = vreg;
	}
	return 0;
}

/* Set the Voltage */
static int emac_set_voltage(struct emac_adapter *adpt, enum emac_vreg_id id,
			    int votage)
{
	int retval = regulator_set_voltage(adpt->vreg[id].vreg, votage, votage);

	if (retval)
		emac_err(adpt,
			 "error:%d set voltage for %s\n",
			 retval, emac_regulator_name[id]);
	else
		adpt->vreg[id].set_voltage = true;
	return retval;
}

/* Enable the regulator */
static int emac_enable_regulator(struct emac_adapter *adpt)
{
	int retval;

	retval = emac_set_voltage(adpt, EMAC_VREG1, EMAC_VREG1_VOLTAGE);
	if (retval)
		goto err;

	retval = regulator_enable(adpt->vreg[EMAC_VREG1].vreg);
	if (retval) {
		emac_err(adpt, "error:%d enable regulator %s\n",
			 retval, emac_regulator_name[EMAC_VREG1]);
		goto err;
	} else {
		adpt->vreg[EMAC_VREG1].enabled = true;
	}

	retval = emac_set_voltage(adpt, EMAC_VREG2, EMAC_VREG2_VOLTAGE);
	if (retval)
		goto err;

	retval = regulator_enable(adpt->vreg[EMAC_VREG2].vreg);
	if (retval) {
		emac_err(adpt, "error:%d enable regulator %s\n",
			 retval, emac_regulator_name[EMAC_VREG2]);
		goto err;
	} else {
		adpt->vreg[EMAC_VREG2].enabled = true;
	}

	retval = regulator_enable(adpt->vreg[EMAC_VREG3].vreg);
	if (retval) {
		emac_err(adpt, "error:%d enable regulator %s\n",
			 retval, emac_regulator_name[EMAC_VREG3]);
		goto err;
	} else {
		adpt->vreg[EMAC_VREG3].enabled = true;
	}
	return 0;
err:
	return retval;
}

/* Disable the regulator */
static void emac_disable_regulator(struct emac_adapter *adpt)
{
	u8 i;

	for (i = 0; i < EMAC_VREG_CNT; i++) {
		struct emac_regulator *vreg = &adpt->vreg[i];

		if (vreg->enabled) {
			regulator_disable(vreg->vreg);
			vreg->enabled = false;
		}

		if (vreg->set_voltage) {
			emac_set_voltage(adpt, i, EMAC_VREG_RESET_VOLTAGE);
			vreg->set_voltage = false;
		}
	}
}

/* LDO init */
static int msm_emac_ldo_init(struct platform_device *pdev,
			     struct emac_adapter *adpt)
{
	int retval = 0;

	retval = emac_get_regulator(pdev, adpt);
	if (retval)
		return retval;

	retval =  emac_enable_regulator(adpt);
	if (retval)
		return retval;
	return 0;
}

/* Probe function */
static int emac_probe(struct platform_device *pdev)
{
@@ -2712,6 +2836,10 @@ static int emac_probe(struct platform_device *pdev)
	if (retval)
		goto err_res;

	retval = msm_emac_ldo_init(pdev, adpt);
	if (retval)
		goto err_ldo_init;

	/* initialize clocks */
	retval = emac_init_clks(adpt);
	if (retval)
@@ -2823,6 +2951,8 @@ err_clk_en:
err_init_phy:
err_clk_init:
	emac_disable_clks(adpt);
err_ldo_init:
	emac_disable_regulator(adpt);
	emac_release_resources(adpt);
err_res:
	free_netdev(netdev);
@@ -2842,6 +2972,7 @@ static int emac_remove(struct platform_device *pdev)
	if (TEST_FLAG(hw, HW_PTP_CAP))
		emac_ptp_remove(netdev);

	emac_disable_regulator(adpt);
	emac_disable_clks(adpt);
	emac_release_resources(adpt);
	free_netdev(netdev);