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

Commit 4a262df5 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm_11ad: add VDD and VDDIO regulators voting"

parents 0a5e0de1 99d1c7f7
Loading
Loading
Loading
Loading
+6 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,9 @@ Required properties:
Optional properties:
Optional properties:
- qcom,sleep-clk-en: GPIO for sleep clock used for low power modes by 11ad card
- qcom,sleep-clk-en: GPIO for sleep clock used for low power modes by 11ad card
- qcom,wigig-en: Enable GPIO connected to 11ad card
- qcom,wigig-en: Enable GPIO connected to 11ad card
- qcom,use-ext-supply: Boolean flag to indicate if 11ad SIP uses external power supply
- vdd-supply: phandle to 11ad VDD regulator node
- vddio-supply: phandle to 11ad VDDIO regulator node


Example:
Example:
	wil6210: qcom,wil6210 {
	wil6210: qcom,wil6210 {
@@ -34,5 +37,8 @@ Example:
		qcom,msm-bus,vectors-KBps =
		qcom,msm-bus,vectors-KBps =
			<100 512 0 0>,
			<100 512 0 0>,
			<100 512 600000 800000>; /* ~4.6Gbps (MCS12) */
			<100 512 600000 800000>; /* ~4.6Gbps (MCS12) */
		qcom,use-ext-supply;
		vdd-supply= <&pm8998_s7>;
		vddio-supply= <&pm8998_s5>;
	};
	};
+263 −0
Original line number Original line Diff line number Diff line
@@ -43,12 +43,27 @@
#define WIGIG_RAMDUMP_SIZE    0x200000 /* maximum ramdump size */
#define WIGIG_RAMDUMP_SIZE    0x200000 /* maximum ramdump size */
#define WIGIG_DUMP_FORMAT_VER   0x1
#define WIGIG_DUMP_FORMAT_VER   0x1
#define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
#define WIGIG_DUMP_MAGIC_VER_V1 0x57474947
#define VDD_MIN_UV	1028000
#define VDD_MAX_UV	1028000
#define VDD_MAX_UA	575000
#define VDDIO_MIN_UV	1950000
#define VDDIO_MAX_UV	2040000
#define VDDIO_MAX_UA	70300


struct device;
struct device;


static const char * const gpio_en_name = "qcom,wigig-en";
static const char * const gpio_en_name = "qcom,wigig-en";
static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";
static const char * const sleep_clk_en_name = "qcom,sleep-clk-en";


struct msm11ad_vreg {
	const char *name;
	struct regulator *reg;
	int max_uA;
	int min_uV;
	int max_uV;
	bool enabled;
};

struct msm11ad_ctx {
struct msm11ad_ctx {
	struct list_head list;
	struct list_head list;
	struct device *dev; /* for platform device */
	struct device *dev; /* for platform device */
@@ -80,6 +95,8 @@ struct msm11ad_ctx {
	void *ramdump_addr;
	void *ramdump_addr;
	struct msm_dump_data dump_data;
	struct msm_dump_data dump_data;
	struct ramdump_device *ramdump_dev;
	struct ramdump_device *ramdump_dev;
	struct msm11ad_vreg vdd;
	struct msm11ad_vreg vddio;
};
};


static LIST_HEAD(dev_list);
static LIST_HEAD(dev_list);
@@ -95,6 +112,218 @@ static struct msm11ad_ctx *pcidev2ctx(struct pci_dev *pcidev)
	return NULL;
	return NULL;
}
}


static int msm_11ad_init_vreg(struct device *dev,
			      struct msm11ad_vreg *vreg, const char *name)
{
	int rc = 0;

	if (!vreg)
		return 0;

	vreg->name = kstrdup(name, GFP_KERNEL);
	if (!vreg->name)
		return -ENOMEM;

	vreg->reg = devm_regulator_get(dev, name);
	if (IS_ERR_OR_NULL(vreg->reg)) {
		rc = PTR_ERR(vreg->reg);
		dev_err(dev, "%s: failed to get %s, rc=%d\n",
			__func__, name, rc);
		kfree(vreg->name);
		vreg->reg = NULL;
		goto out;
	}

	dev_info(dev, "%s: %s initialized successfully\n", __func__, name);

out:
	return rc;
}

static int msm_11ad_release_vreg(struct device *dev, struct msm11ad_vreg *vreg)
{
	if (!vreg || !vreg->reg)
		return 0;

	dev_info(dev, "%s: %s released\n", __func__, vreg->name);

	devm_regulator_put(vreg->reg);
	vreg->reg = NULL;
	kfree(vreg->name);

	return 0;
}

static int msm_11ad_init_vregs(struct msm11ad_ctx *ctx)
{
	int rc;
	struct device *dev = ctx->dev;

	if (!of_property_read_bool(dev->of_node, "qcom,use-ext-supply"))
		return 0;

	rc = msm_11ad_init_vreg(dev, &ctx->vdd, "vdd");
	if (rc)
		goto out;

	ctx->vdd.max_uV = VDD_MAX_UV;
	ctx->vdd.min_uV = VDD_MIN_UV;
	ctx->vdd.max_uA = VDD_MAX_UA;

	rc = msm_11ad_init_vreg(dev, &ctx->vddio, "vddio");
	if (rc)
		goto vddio_fail;

	ctx->vddio.max_uV = VDDIO_MAX_UV;
	ctx->vddio.min_uV = VDDIO_MIN_UV;
	ctx->vddio.max_uA = VDDIO_MAX_UA;

	return rc;

vddio_fail:
	msm_11ad_release_vreg(dev, &ctx->vdd);
out:
	return rc;
}

static void msm_11ad_release_vregs(struct msm11ad_ctx *ctx)
{
	msm_11ad_release_vreg(ctx->dev, &ctx->vdd);
	msm_11ad_release_vreg(ctx->dev, &ctx->vddio);
}

static int msm_11ad_cfg_vreg(struct device *dev,
			     struct msm11ad_vreg *vreg, bool on)
{
	int rc = 0;
	int min_uV;
	int uA_load;

	if (!vreg || !vreg->reg)
		goto out;

	if (regulator_count_voltages(vreg->reg) > 0) {
		min_uV = on ? vreg->min_uV : 0;
		rc = regulator_set_voltage(vreg->reg, min_uV, vreg->max_uV);
		if (rc) {
			dev_err(dev, "%s: %s set voltage failed, err=%d\n",
					__func__, vreg->name, rc);
			goto out;
		}
		uA_load = on ? vreg->max_uA : 0;
		rc = regulator_set_optimum_mode(vreg->reg, uA_load);
		if (rc >= 0) {
			/*
			 * regulator_set_optimum_mode() returns new regulator
			 * mode upon success.
			 */
			dev_dbg(dev,
				  "%s: %s regulator_set_optimum_mode rc(%d)\n",
				  __func__, vreg->name, rc);
			rc = 0;
		} else {
			dev_err(dev,
				"%s: %s set mode(uA_load=%d) failed, rc=%d\n",
				__func__, vreg->name, uA_load, rc);
			goto out;
		}
	}

out:
	return rc;
}

static int msm_11ad_enable_vreg(struct msm11ad_ctx *ctx,
				struct msm11ad_vreg *vreg)
{
	struct device *dev = ctx->dev;
	int rc = 0;

	if (!vreg || !vreg->reg || vreg->enabled)
		goto out;

	rc = msm_11ad_cfg_vreg(dev, vreg, true);
	if (rc)
		goto out;

	rc = regulator_enable(vreg->reg);
	if (rc) {
		dev_err(dev, "%s: %s enable failed, rc=%d\n",
				__func__, vreg->name, rc);
		goto enable_fail;
	}

	vreg->enabled = true;

	dev_info(dev, "%s: %s enabled\n", __func__, vreg->name);

	return rc;

enable_fail:
	msm_11ad_cfg_vreg(dev, vreg, false);
out:
	return rc;
}

static int msm_11ad_disable_vreg(struct msm11ad_ctx *ctx,
				 struct msm11ad_vreg *vreg)
{
	struct device *dev = ctx->dev;
	int rc = 0;

	if (!vreg || !vreg->reg || !vreg->enabled)
		goto out;

	rc = regulator_disable(vreg->reg);
	if (rc) {
		dev_err(dev, "%s: %s disable failed, rc=%d\n",
				__func__, vreg->name, rc);
		goto out;
	}

	/* ignore errors on applying disable config */
	msm_11ad_cfg_vreg(dev, vreg, false);
	vreg->enabled = false;

	dev_info(dev, "%s: %s disabled\n", __func__, vreg->name);

out:
	return rc;
}

static int msm_11ad_enable_vregs(struct msm11ad_ctx *ctx)
{
	int rc = 0;

	rc = msm_11ad_enable_vreg(ctx, &ctx->vdd);
	if (rc)
		goto out;

	rc = msm_11ad_enable_vreg(ctx, &ctx->vddio);
	if (rc)
		goto vddio_fail;

	return rc;

vddio_fail:
	msm_11ad_disable_vreg(ctx, &ctx->vdd);
out:
	return rc;
}

static int msm_11ad_disable_vregs(struct msm11ad_ctx *ctx)
{
	if (!ctx->vdd.reg && !ctx->vddio.reg)
		goto out;

	/* ignore errors on disable vreg */
	msm_11ad_disable_vreg(ctx, &ctx->vdd);
	msm_11ad_disable_vreg(ctx, &ctx->vddio);

out:
	return 0;
}

static int ops_suspend(void *handle)
static int ops_suspend(void *handle)
{
{
	int rc;
	int rc;
@@ -124,6 +353,9 @@ static int ops_suspend(void *handle)


	if (ctx->sleep_clk_en >= 0)
	if (ctx->sleep_clk_en >= 0)
		gpio_direction_output(ctx->sleep_clk_en, 0);
		gpio_direction_output(ctx->sleep_clk_en, 0);

	msm_11ad_disable_vregs(ctx);

	return rc;
	return rc;
}
}


@@ -139,6 +371,13 @@ static int ops_resume(void *handle)
		return -ENODEV;
		return -ENODEV;
	}
	}


	rc = msm_11ad_enable_vregs(ctx);
	if (rc) {
		dev_err(ctx->dev, "msm_11ad_enable_vregs failed :%d\n",
			rc);
		return rc;
	}

	if (ctx->sleep_clk_en >= 0)
	if (ctx->sleep_clk_en >= 0)
		gpio_direction_output(ctx->sleep_clk_en, 1);
		gpio_direction_output(ctx->sleep_clk_en, 1);


@@ -173,6 +412,9 @@ err_disable_power:


	if (ctx->sleep_clk_en >= 0)
	if (ctx->sleep_clk_en >= 0)
		gpio_direction_output(ctx->sleep_clk_en, 0);
		gpio_direction_output(ctx->sleep_clk_en, 0);

	msm_11ad_disable_vregs(ctx);

	return rc;
	return rc;
}
}


@@ -458,6 +700,19 @@ static int msm_11ad_probe(struct platform_device *pdev)


	/*== execute ==*/
	/*== execute ==*/
	/* turn device on */
	/* turn device on */
	rc = msm_11ad_init_vregs(ctx);
	if (rc) {
		dev_err(ctx->dev, "msm_11ad_init_vregs failed :%d\n",
			rc);
		return rc;
	}
	rc = msm_11ad_enable_vregs(ctx);
	if (rc) {
		dev_err(ctx->dev, "msm_11ad_enable_vregs failed :%d\n",
			rc);
		goto out_vreg;
	}

	if (ctx->gpio_en >= 0) {
	if (ctx->gpio_en >= 0) {
		rc = gpio_request(ctx->gpio_en, gpio_en_name);
		rc = gpio_request(ctx->gpio_en, gpio_en_name);
		if (rc < 0) {
		if (rc < 0) {
@@ -547,6 +802,10 @@ out_set:
		gpio_free(ctx->gpio_en);
		gpio_free(ctx->gpio_en);
out_req:
out_req:
	ctx->gpio_en = -EINVAL;
	ctx->gpio_en = -EINVAL;
	msm_11ad_disable_vregs(ctx);
out_vreg:
	msm_11ad_release_vregs(ctx);

	return rc;
	return rc;
}
}


@@ -568,6 +827,10 @@ static int msm_11ad_remove(struct platform_device *pdev)
	}
	}
	if (ctx->sleep_clk_en >= 0)
	if (ctx->sleep_clk_en >= 0)
		gpio_free(ctx->sleep_clk_en);
		gpio_free(ctx->sleep_clk_en);

	msm_11ad_disable_vregs(ctx);
	msm_11ad_release_vregs(ctx);

	return 0;
	return 0;
}
}